问题描述
我试图在执行保存之前在数据库中捕获实体数据,以创建卷影副本。
我在Spring应用程序中实现了以下EntityListener
:
public class CmsListener {
public CmsListener() {
}
@PreUpdate
private void createShadow(CmsModel entity) {
EntityManager em = BeanUtility.getBean(EntityManager.class);
CmsModel p = em.find(entity.getClass(),entity.getId());
System.out.println(entity);
}
}
entity
确实包含要保存的实体对象,然后我使用另一种工具注入了EntityManager
,该工具运行良好-但由于某种原因,该实体已经保存了到数据库。 CmsModel p = em.find(...)
的输出结果与entity
中的数据相同。
为什么JPA / hibernate在调用@PreUpdate之前保留更改?我该如何预防?
解决方法
我认为这是因为em.find实际上并不查询数据库,而是从缓存中获取对象,因此它实际上获取了所引用的相同对象实体(已应用更改)。
您可以检查数据库日志中是否有查询查询以获取用于entity.id的数据,以验证是否确实存在这种情况,或者可以在createShadow()中添加断点并查看当时实体的数据库条目会调用该函数以自己查看更改是否已在那时应用到数据库。
要真正解决问题并获取卷影副本,您可以通过本机查询直接从数据库中获取对象。 这是一个未经测试的示例,看起来像什么:
public CmsModel fetchCmsModelDirectly(){
Query q = em.createNativeQuery("SELECT cm.id,cm.value_a,cm.value_b FROM CmsModel cm",CmsModel.class);
try{
return q.getSingleResult();
}catch(NoResultException e){
return null;
}
}
,
您是否检查实体是否真的更新到数据库?我的怀疑是所做的更改仅更新为持久性上下文(缓存)。当实体在侦听器中被查询回来时,将从缓存中返回一个实体。因此它们是相同的。
这是大多数ORM(在这种情况下为JPA)的默认行为,以加快数据查找速度。 ORM框架将负责在持久性上下文和数据库之间进行同步。通常在提交交易时。