首页 文章

JPA:如何管理id(或business-id)?仍然是等于/ hashcode的pb

提问于
浏览
1

我是Hibernate,Spring,JPA框架的初学者 . 暂时,我正在尝试使用Spring 3.1.1创建一个简单的架构 - 带有Hibernate 4实现的JPA .

目前,为了不依赖于我的数据库,我使用TableGenerator创建了一些ID:

@Id
@Column(name = "AIR_ID", unique = true, nullable = false)
@TableGenerator(name="aircraftSeqStore", 
    table="T_S_APP_SEQ_STORE_AST", 
    pkColumnName="AST_SEQ_NAME",
    valueColumnName = "AST_SEQ_VALUE",
    pkColumnValue = "T_R_AIRCRAFT_AIR.AIR_ID", 
    allocationSize=1)
@GeneratedValue(strategy=GenerationType.TABLE, 
    generator="aircraftSeqStore")       
private Integer id;

在我的研究之后,在阅读了“不要让我自己偷了 - 偷你的身份”这篇文章后,我真的不明白如何管理我的ID .

我应该修改我的实体以用指定的值替换它们(如何在JPA中执行?)并且我应该生成一个UUID来直接在创建瞬态对象时影响id吗?

在许多表中,我有一些简单的数据(id,name) . 我以为我可以在名称属性上管理hashcode和equals方法,这些方法是唯一的,但在创建对象时也没有受到影响....(所以我认为同样的pb,id为null?) .

有关信息,我有一个表示多连接表的实体(此连接表中为3 FK) .

那么你对我有什么建议?为性能生成UUID是不是很糟糕?


EDIT :

这个实体可行吗?

@Id
@Column(name = "AIR_ID", unique = true, nullable = false)
@TableGenerator(name="aircraftSeqStore", 
    table="T_S_APP_SEQ_STORE_AST", 
    pkColumnName="AST_SEQ_NAME",
    valueColumnName = "AST_SEQ_VALUE",
    pkColumnValue = "T_R_AIRCRAFT_AIR.AIR_ID", 
    allocationSize=1)
@GeneratedValue(strategy=GenerationType.TABLE, 
    generator="aircraftSeqStore")       
private Integer id;

@Column(name = "AIR_BUSINESS_ID", unique = true, nullable = false)
private String uuid = IdGenerator.createId();

public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || !(o instanceof Aircraft))
        return false;

    Aircraft other = (Aircraft)o;

    if (uuid == null) return false;
    return uuid .equals(other.getUuid ());
}

public int hashCode() {
    if (uuid  != null) {
        return uuid .hashCode();
    } else {
        return super.hashCode();
    }
}

谢谢 .

3 回答

  • 0

    正如每个问题一样,完整但很少有用的答案是:这取决于 .

    更有用的变体是:

    我大部分时间都使用GenerationType.Auto,并且不实现equals和hashcode .

    结果是:

    • 你可以很好地比较实体对象,只要它们位于同一个会话中,因为hibernate将确保每个数据库行由每个会话的单个实例表示 .

    • equals和hashcode随着时间的推移是稳定的,因此您可以将对象放在HashSet中,更改对象并再次将它们取出 .

    • 如果要使用来自不同Sessions的对象,则必须通过实现Comparator来显式比较id或id hashcode或某些业务键 . 决定使用和实现它的额外努力将提醒你,你实际上正在做一些违背Hibernate的事情 .

    关于性能:根据数据库和用例,UUID具有较高的性价比,因为它们相当大或获得性能,因为它们可以在客户端上创建,从而节省了数据库往返 . 大多数情况下,应用程序中的其他故障(特别是在使用Hibernate时)比ID生成的任何影响都要大 .

  • 0

    通常我用:

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)     
        private Integer id
    

    并让持久性提供者选择正确的 . 希望这对你有所帮助

  • 3

    我最近问了一个问题,探讨了通常模式的替代方案:Are there any gotchas with this JPA "cached hashCode" pattern?

    我包含了一个我通常用 @Entity 类做的例子 - 在构造时生成 UUID . UUID 碰撞的概率非常小,以至于 UUID s因为他们觉得存在性能损失 . 我没有看到性能与 Integer 有任何变化,但我认为 Integer 碰撞的可能性很小,足以引起关注 .

    @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);
    }
    

相关问题