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

时间:2012-08-10 10:10:45

标签: java hibernate jpa

我是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是不是很糟糕?


编辑:

这个实体是否可行?

@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 :(得分:3)

与每个问题一样,完整但很少有用的答案是:它取决于。

更有用的变体是:

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

结果是:

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

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

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

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

答案 1 :(得分:0)

通常我使用:

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

让持久性提供者选择正确的。 希望这能帮到你

答案 2 :(得分:0)

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

我提供了一个我通常用@Entity类做的例子 - 在构造时生成UUIDUUID碰撞的概率很小,你最好担心宇宙射线。有些人不喜欢UUID,因为他们觉得有性能损失。我没有看到性能与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);
}