Hibernate 在@PostPersist中修改的字段在数据库中不更新
MyEntity是一个具有生成id的经典JPA实体。我希望自动将字段(myStringField)设置为基于id的值。在本例中,如果id为43,我希望将其设置为“foo43” 由于id是由DB自动生成的,因此在em.persist(myEntity)调用之前它是空的。但是在persist之后,它有一个由Hibernate分配的id(在DB序列上称为NEXTVAL)。因此,我考虑声明@PostPersist方法,如下所示:Hibernate 在@PostPersist中修改的字段在数据库中不更新,hibernate,jpa,Hibernate,Jpa,MyEntity是一个具有生成id的经典JPA实体。我希望自动将字段(myStringField)设置为基于id的值。在本例中,如果id为43,我希望将其设置为“foo43” 由于id是由DB自动生成的,因此在em.persist(myEntity)调用之前它是空的。但是在persist之后,它有一个由Hibernate分配的id(在DB序列上称为NEXTVAL)。因此,我考虑声明@PostPersist方法,如下所示: package ...; import javax.persistenc
package ...;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PostPersist;
@Entity
public class MyEntity {
@Id @GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String myStringField;
@PostPersist
public void postPersist(){
System.out.println("The id = " + id);
this.myStringField = "foo" + id;
}
public String getMyStringField() {
return myStringField;
}
...
}
以下是一些创建和保存实体的代码:
package ...;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Transactional
@Service
public class MySpringBean {
@PersistenceContext EntityManager em;
public void createMyEntity() {
MyEntity myEntity = new MyEntity();
em.persist(myEntity);
System.out.println(myEntity.getMyStringField());
}
}
它打印以下输出:
The id = 47
foo47
这很好。但是,在数据库中,myStringField字段为空!有人知道为什么吗
我确实希望在MyEntity.postPersist()方法中实体会被标记为dirty,并且在刷新过程中事务结束时会发生更新。但显然不是
我使用HibernateV4.2.4
有人知道为什么这个数据库记录有空值吗?您是在持久化后执行的,所以它发生在写入数据库之后 根据对规格说明的回答
这些数据库操作可能在调用持久化、合并或删除操作后直接发生,也可能在刷新操作发生后直接发生。
保存MyEntity后@PostPersist代码正在运行。因此,如果要确保使用更新的值“foo”+id保存字段myStringField,那么在@PostPersist代码之后,需要再次保存实体
因此,如果您将代码更改为:
MyEntity myEntity = new MyEntity();
em.persist(myEntity);
em.persist(myEntity);
理论上,这应该正确地保存更新后的myStringField。不过这有点尴尬。不确定你的整个用例,但是你可以考虑在数据库本身写一个“插入触发器”,它会帮你处理这个问题。我做了额外的测试,事实上,在刷新期间调用了@PostPersist(可能是因为在刷新期间发送了SQL插入)。总之,事情的发生顺序是:1。em.persist(),1.1 NEXTVAL发送到DB并分配myEntity.id,到达@Transactional方法的2个结尾并执行刷新。2.1向DB发送插入信息。2.2@PostPersist已调用。2.2.1 myEntity.myStringField已分配,实体已脏。然后不再执行进一步的刷新(以及脏检查和更新)=>无数据库保存。非常感谢 使用
@PrePersist
相反,但是您的方法字段生成对我来说是不正确的,因为如果您的myStringField即将成为一个业务id,不同于jpa id,那么您应该假设它是在bean初始化时创建的
有关如何处理业务id的更多示例,我建议您查看关于equals()/hashcode()困境的线程,特别是下面的回答:要回答您的问题,您不应该在数据层中做这种事情。插入和更新应该由业务逻辑层处理 但是如果在数据层中确实需要@PrePersist,请使用它