您在这里遇到两个独立的问题。让我们先轻松一点。
javax.ejb.EJBTransactionRolledbackException:实体不受管理
该
List查询返回的对象 本身
不是
Entity,因此您不能这样
.refresh做。实际上,这就是异常所抱怨的。您正在要求对
EntityManager根本未知的对象执行某项操作
Entity。
如果您想要
.refresh一堆东西,请遍历它们并逐一进行
.refresh。
刷新ItemStatus的列表
您正在
Session以某种您所不希望的方式与Hibernate的-
level缓存进行交互。从Hibernate文档:
对于附加到特定会话的对象(即,在会话范围内)…数据库身份的JVM身份由Hibernate保证。
这样做的影响
Query.getResultList()是,您不必一定要恢复数据库的最新状态。
在
Query您运行确实是越来越匹配查询实体ID列表。
Session高速缓存中已经存在的任何ID都会与已知实体匹配,而没有根据数据库状态填充的任何ID。先前已知的实体
根本不会 从数据库中刷新。
这意味着
Query在同一事务中两次执行from 之间,如果数据库中某个已知实体的某些数据发生了更改,则第二个Query将 不
接受该更改。但是,它将选择一个全新的
ItemStatus实例(除非您使用的是查询缓存,否则我认为您不是)。
长话短说:使用Hibernate,只要想在单个事务中加载一个实体,然后从数据库中对该实体进行其他更改,就必须显式地
.refresh(entity)。
您如何处理此问题取决于您的用例。我可以想到两种选择:
- 必须将DAO绑定到事务的生命周期,并懒惰地初始化
List<ItemStatus>
。随后的调用DAO.refreshList
通过List
和进行迭代.refresh(status)
。如果您还需要新添加的实体,您应该运行Query
和 也 刷新知ItemStatus对象。 - 开始新交易。听起来像是您与@Perception进行的聊天,但这不是一个选择。
一些附加说明
关于使用查询提示的讨论。这就是为什么它们不起作用的原因:
org.hibernate.cacheable = false
仅在使用查询缓存时才有意义,仅在非常特殊的情况下才建议这样做。即使您正在使用它,也不会影响您的情况,因为查询缓存包含对象ID,而不是数据。
org.hibernate.cacheMode = REFRESH 这是Hibernate
二级缓存的指令。如果打开了第二级缓存,并且您是从不同的事务发出两个查询,那么您将在第二个查询中获得过时的数据,并且此伪指令将解决此问题。但是,如果您在两个查询中处于同一会话中,则只会使用第二级缓存来避免为this的新实体加载数据库
Session。



