gpt4 book ai didi

Hibernate:什么时候需要实现 equals() 和 hashCode(),如果需要,如何实现?

转载 作者:行者123 更新时间:2023-12-02 23:17:04 25 4
gpt4 key购买 nike

基于various bad experiences作为一名 Java 程序员,我的经验法则是仅实现 equals()hashCode()在不可变对象(immutable对象)上,对象的两个实例确实可以互换。

基本上我想避免像 HashMap 这样的情况该链接中的关键问题,或如下所示:

  1. 获取具有特定身份的东西。
  2. 修改它。
  3. 将其添加到集合中。
  4. (稍后)获取具有相同身份的另一个东西。
  5. 修改它。
  6. 将其添加到同一组中。
  7. 没有注意到这个添加实际上并没有发生,因为集合认为该东西已经存在。
  8. 用集合中的东西做一些事情。
  9. 没有注意到步骤 (5) 中的更改被忽略,并且我们仍然具有步骤 (2) 中的状态。

总的来说,在我的 Java 职业生涯中,我 haven't found a lot of use对于 equals() 除了(1)值对象和(2)将事物放入集合中。我还发现不变性+复制和修改构造函数/构建器通常比 setter 更快乐。两个对象可能具有相同的 ID,并且可能表示相同的逻辑实体,但如果它们具有不同的数据(如果它们表示概念实体在不同时间的快照),那么它们就不是 equal() .

无论如何,我现在在一家 Hibernate 商店,而我更精通 Hibernate 的同事告诉我这种方法行不通。具体来说,该主张似乎是在以下场景中——

  1. Hibernate 从数据库加载一个东西——我们称之为实例 h1 .
  2. 这个东西被整理并通过网络服务发送到某个地方。
  3. 网络服务客户端对其进行修改并发送回修改后的版本。
  4. 修改后的版本在服务器上解码 - 我们将其称为实例 h4 .
  5. 我们希望 Hibernate 通过修改来更新数据库。

--除非 h1.equals(h4) (或者也许是 h4.equals(h1) ,我不清楚,但我希望它是可传递的,无论如何),Hibernate 将无法判断这些是同一件事,并且会发生不好的事情。

所以,我想知道的是:

  • 这是真的吗?
  • 如果是这样,为什么? Hibernate 使用什么 equals()为了?
  • 如果 Hibernate 需要 h1h4为了平等,它(以及我们如何)如何跟踪哪一个是修改版本?
<小时/>

注意:我已阅读 Implementing equals() and hashCode()在 Hibernate 文档中,它没有处理我担心的情况,至少没有直接解决,也没有详细解释 Hibernate 真正需要的 equals()hashCode()equals and hashcode in Hibernate 的答案也没有,不然我就懒得发这个了。

最佳答案

首先,您最初的想法,即您应该仅在不可变对象(immutable对象)上实现 equals() 和 hashCode() ,当然可行,但它比需要的更严格。您只需要这两个方法来依赖不可变字段。任何值可能更改的字段都不适合在这两种方法中使用,但其他字段不必是不可变的。

话虽如此,Hibernate 通过比较它们的主键知道它们是同一个对象。这导致许多人编写这两个方法来依赖主键。 Hibernate 文档建议您不要这样做,但许多人会忽略这个建议,但不会遇到太大麻烦。这意味着在实体被持久化之前你不能将它们添加到集合中,这是一个并不难接受的限制。

Hibernate 文档建议使用业务 key 。但业务 key 应该依赖于唯一标识对象的字段。 Hibernate 文档说“使用由独特的、通常不可变的属性组合而成的业务 key ”。我使用在数据库中对其具有唯一约束的字段。因此,如果您的 Sql CREATE TABLE 语句将约束指定为

CONSTRAINT uc_order_num_item UNIQUE (order_num, order_item)

那么这两个字段就可以成为您的业务关键。这样,如果您更改其中之一,Hibernate 和 Java 都会将修改的对象视为不同的对象。当然,如果您确实更改了这些“不可变”字段之一,则会弄乱它们所属的任何 Set。因此,我想您需要清楚地记录哪些字段包含业务 key ,并在编写应用程序时了解业务 key 中的字段永远不应为持久对象进行更改。我明白为什么人们忽略这些建议而只使用主键。但是您可以像这样定义主键:

CONSTRAINT pk_order_num_item PRIMARY KEY (order_num, order_item)

你仍然会遇到同样的问题。

就个人而言,我希望看到一个指定业务 key 中每个字段的注释,并进行 IDE 检查来检查我是否修改了它以保留持久对象。也许这个要求太高了。

另一种解决所有这些问题的方法是使用 UUID 作为主键,该主键是您在第一次构造非持久实体时在客户端上生成的。由于您永远不需要向用户显示它,因此一旦设置它,您的代码就不太可能更改它的值。这使您可以编写始终有效且彼此保持一致的 hashCode() 和 equals() 方法。

还有一件事:如果您想避免将对象添加到已包含其不同(修改后)版本的 Set 中的问题,唯一的方法是在添加之前始终询问该集合是否已经存在。然后您可以编写代码来处理这种特殊情况。

关于Hibernate:什么时候需要实现 equals() 和 hashCode(),如果需要,如何实现?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9089266/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com