我正在使用jpa和hibernate(3.2.7)作为orm实现。 我有一个实体被修改然后合并。 我在这个实体上也有一个@EntityListeners,以确保一些属性被重视。
如果我在合并之前更改了值,然后在Listener中的@PreUpdate方法中更改了该值,则设置原始值,我在实体结果上的版本会增加,但在数据库版本上有先前的值。 我认为这是由于对象没有改变,因此在db上它没有更新,但实体上的版本增加了,而不是在刷新后恢复。
为了更好地解释,我有这个对象:
@Entity
@EntityListeners({MyListener.class})
public class MyEntity {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String myValue;
@Version
private Long version ;
}
和这个听众:
public class MyListener {
@PreUpdate
public void preUpdate(MyEntity ua) {
ua.setMyValue("default");
}
}
现在假设我在db上有一个具有以下值的对象:(id = 1,myValue ='defalut',version = 1)。我读取此对象,分离,将其传递给客户端并使用myValue ='new'将其恢复并执行合并操作(侦听器将myValue更改为'default',因此将对象结果未修改为db),刷新并退出事务(所以承诺)。 之后我在我的对象上找到version = 2,但在db。上找到版本= 1。
这是一个hibernate错误吗?还是一个Jpa bug?
答案 0 :(得分:2)
我想说这是一种预期的行为。根据{{3}},@PreUpdate
是“在数据库更新操作之前执行的”。因此,Hibernate已经发现它必须通过运行脏检查来执行UPDATE,并使其返回true。
在@PreUpdate
之后不能进行脏检查,因为除非脏检查为真,否则Hibernate不应该调用@PreUpdate
。如果要运行更新,则应增加版本。
您是否考虑过使用@PrePersist
而非@PreUpdate
的听众?我相信这个过程的早期就是预先检查,因此有你想要的行为。
答案 1 :(得分:0)
对我来说,它看起来像规范违规。或者这可能是措辞过于强烈,可能更好地说这样的角落案例并没有明确规定。当版本应该更新时,JPA 1.0(Hibernate 3.2.7是其中一个实现)规范非常清楚:
版本属性由持久性提供程序运行时更新 当对象被写入数据库时。
同时在被调用实体中设置基本属性(JPA 2.0):
生命周期回调方法可以修改非关系状态 调用它的实体。