【发布时间】:2015-03-20 23:52:05
【问题描述】:
我正在使用 Spring Data JpaRepository,并将 Hibernate 作为 JPA 提供程序。
通常在直接使用 Hibernate 时,EntityManager#persist() 和 EntityManager#save() 之间的决定取决于程序员。使用 Spring Data 存储库,只有 save()。我不想在这里讨论利弊。让我们考虑以下简单的基类:
@MappedSuperclass
public abstract class PersistableObject {
@Id
private String id;
public PersistableObject(){
this.id = UUID.randomUUID().toString();
}
// hashCode() and equals() are implemented based on equality of 'id'
}
使用这个基类,Spring Data 存储库无法判断哪些实体是“新的”(尚未保存到 DB),因为在这种情况下,对 id == null 的常规检查显然不起作用,因为 UUID 是热切分配以确保equals()和hashCode()的正确性。所以存储库似乎做的是总是调用EntityManager#merge()——这对于瞬态实体来说显然是低效的。
问题是:我如何告诉 JPA(或 Spring Data)一个实体是新的,如果可能的话它使用EntityManager#persist() 而不是#merge()?
我正在考虑这些方面的事情(使用 JPA 生命周期回调):
@MappedSuperclass
public abstract class PersistableObject {
@Transient
private boolean isNew = true; // by default, treat entity as new
@PostLoad
private void loaded(){
// a loaded entity is never new
this.isNew = false;
}
@PostPersist
private void saved(){
// a saved entity is not new anymore
this.isNew = false;
}
// how do I get JPA (or Spring Data) to use this method?
public boolean isNew(){
return this.isNew;
}
// all other properties, constructor, hashCode() and equals same as above
}
【问题讨论】:
-
equals() 和 hashCode() 应该基于业务密钥而不是数据存储密钥。在性能方面,UUID 也是不好的主键。
-
感谢您的警告。不幸的是,几乎不可能为这个问题想出一个通用的解决方案,没有人玩“坏习惯!”卡片。最后,这是一个权衡:我宁愿自己管理身份并拥有一个干净的 hashCode() 和 equals(),而不是让 Hibernate 查询数据库只是为了检索 ID 序列中的下一个条目。
标签: spring hibernate jpa spring-data-jpa