java - 这个 JPA "cached hashCode"模式有什么陷阱吗?

标签 java hibernate jpa persistence

我在 #hibernate IRC 上有人与我分享了以下(部分)模式

@Entity
public MyEntity() {

  ... primary key, object properties, getters/setters go here ...    

  @Column(nullable=false)
  private int hashCode;

  public MyEntity() {
     hashCode += id;
  }

  private final Set<String> tags = Sets.newHashSet();

  public void addTag(String tag) {
     if(tags.add(tag)) {
         hashCode += tag.hashCode();
     }
  }

  public void removeTag(String tag) {
     if(tags.remove(tag) {
        hashCode -= tag.hashCode();
     }
  }

  public void hashCode() {
    return hashCode;
  }

  ... http://www.artima.com/lejava/articles/equality.html style equals ...
}

可以将其称为“分段更新的缓存哈希码”。 (这绝对不是一些评论者似乎相信的“业务键”模式。“业务键”模式需要一个具有唯一性约束的列,如用户名,用于平等测试)。

在 JPA/Hibernate 中使用时,这意味着 @Entity 可以具有与 JBoss Equals and HashCode article 中的“eq/hC with buisness [sic] key”类似的优点。 ,但其行为方式与开发人员期望的任何普通 Javabean 对象的行为方式相同(即无需将对象视为数据库行):在被持久化到 DB 之前;在 EAGER 获取模式下的 Transaction 之后;并在任何时候使用 LAZYTransactionEXTENDED 模式下获取。

但是,确保 hashCode 始终正确更新可能是一个真正的挑战。

这里有人对这种模式有任何经验吗?您能否分享您对此的发现(积极的和消极的)?我对 Gotchas 非常感兴趣,但我对评论完全不感兴趣声称某些东西是“坏的”,却没有关于为什么它是坏的可靠论据。

请注意,我知道 The JPA hashCode() / equals() dilemma ,但我认为该讨论实际上并未涵盖这种模式。

这种模式最初是为了避免在 @Entity 中加载嵌套的 Collection 时出现问题而提出的,例如在 Hibernate LazyInitializationException on find() with EAGER @ElementCollection 中遇到的问题。 .

更新:一些评论者对现有方法非常感兴趣。为免生疑问,我只对这种新模式的优点感兴趣。供您引用,也请您不要再说您认为 equals/hashCode 应该如何实现,请注意我多年来一直为我的 @Entity 使用以下模式:

@Id
private UUID id = UUID.randomUUID();

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (!(obj instanceof MY_CLASS) || id == null)
        return false;
    MY_CLASS other = (MY_CLASS) obj;
    return id.equals(other.id);
}

@Override
public int hashCode() {
    Preconditions.checkNotNull(id, "id must be set before @Entity.hashCode can be called");
    return id.hashCode();
}

我最近才尝试了一些新的东西,看看我是否真的需要像这样的单独方法

public boolean hasSameProperties(Note other) {
    Preconditions.checkNotNull(other);
    if (this == other)
        return true;
    return Objects.equal(source, other.source)
            && Objects.equal(title, other.title)
            && Objects.equal(tags, other.tags)
            && Objects.equal(contents, other.contents);
}

最佳答案

这个业务 key 不是唯一的,所以它似乎是 equals() 的一个糟糕选择。

业务 key 1002 添加了标签 500 和标签 -502,业务 key 995 添加了标签 3 和标签 2?这些对象真的意味着相等吗?

对于您的特定实体服务的任何目的,32 位数字的相对较低的冲突风险可能是可以容忍的,但是将某些东西称为“模式”时,人们希望它实际上是正确的,而不仅仅是任意不可能失败对于给定的数据大小。

关于java - 这个 JPA "cached hashCode"模式有什么陷阱吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11730379/

相关文章:

java - csv 文件的 java.util.Scanner 的正则表达式?

java - 我想找到以 <br> 分隔的日期的 xpath

java - 如何从 Eclipse 中的接口(interface)导航到实现类?

java - Spring数据-根据先前的插入插入数据

java - 具有动态方案的 Jpa

java - 如何强制在 @Entity 和 @ElementCollection 之间生成外键?

java - 映射通过引用 com.bookstore.entity.Book.detailOrders 中的未知目标实体属性 : com. bookstore.entity.DetailOrder.books

java - x.person 上的@OneToOne 或@ManyToOne 引用未知实体 : y. Person - 继承问题

java - @NamedQueries,在实体中创建一个新查询

java - 使用 Spring Roo Activity 记录模式将实体保存回数据库