在提交之前不会通过查询检索持久化实体
Posted
技术标签:
【中文标题】在提交之前不会通过查询检索持久化实体【英文标题】:Persisted entity isn't retrieved by query until commit 【发布时间】:2012-05-08 19:11:57 【问题描述】:我正在使用带有扩展持久性上下文的有状态会话 bean,以及以下 @TransactionAttribute 设置:
@Stateful(...)
@TransactionAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class StatefulExtendedEJBBea
@PersistenceContext(unitName = "JPAModel", type = PersistenceContextType.EXTENDED)
private EntityManager em;
...
/**
* With the REQUIRED txn attribute, we can ensure that each time
* this method is called a new transaction is created and any
* pending changes in the persistence context are committed.
*/
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void commitTransaction()
/** <code>select o from Departments o</code> */
public List<Departments> getDepartmentsFindAll()
return em.createNamedQuery("Departments.findAll").getResultList();
public <T> T persistEntity(T entity)
em.persist(entity);
return entity;
在此示例中需要指出的一些重要事项:
-
调用persistEntity() 方法时没有开始交易,
因为 bean 级别的 @TransactionAttribute(NOT_SUPPORTED)
环境。
txn 仅在以下情况下开始和完成
调用 commitTransaction() 方法,因为它被注解了
@TransactionAttribute(必需)。
这种方法允许持久化新实体(以及它们的 ID 由 JPA 生成和自动分配,使用 @GeneratedValue),而无需 JPA 急切地在数据库中发出 INSERT stmt。因此,我可以在分配任何属性值之前立即保留实体,因为 NOT NULL 列约束尚未验证。只有在调用 commitTransaction() 方法时,JPA 才会执行 INSERT stmt 并执行 COMMIT。
现在,这似乎正如我预期的那样奏效,并具有上面列出的好处。我遇到的问题是,在调用 commitTransaction() 之前,我无法通过 JPQL 查询检索新持久的实体。新持久化的实体似乎由持久化上下文管理,因为我可以在调用persistEntity() 后继续更新它们,并且当我调用commitTransaction() 时,所有后续更改都会正确保存到数据库中。但是,在我发出提交之前,它们似乎并不在查询缓存中。
我猜我在提交时间之前抑制 txn 的策略正在以某种方式影响查询结果。
我是否可以使用查询提示来强制将持久化(在事务之外)但未提交的实体包含在 JPQL 查询中?
TIA
【问题讨论】:
查询总是转到数据库。如果您的实体不在数据库中,您的查询将找不到它们。 好的,所以当 JPA 执行 JPQL stmt 时,它会发出初步查询以仅检索 PK 值?然后它遍历这些 PK 值,在其缓存中找到任何匹配的实体,并且只发出一个完整的查询,其中 where 子句是未找到的 PK 列表? 当你有一个二级缓存和一个查询缓存时,或多或少会发生这种情况,使用 Hibernate(不知道其他实现)。但我不明白这与你的问题有什么关系。 顺便说一句,感谢您的回复。我问是因为它解释了为什么它找不到我的待处理(持久但尚未插入)实体。我想它对 JPA 的要求太多了,以确定是否有任何此类挂起的实体与查询结果匹配,如果匹配则包括它们。 【参考方案1】:您可以在提交之前调用flush()将更改写入数据库。
见,http://en.wikibooks.org/wiki/Java_Persistence/Persisting#Flush
EntityManager 上还有一个刷新模式,它将在每次查询之前触发刷新,默认为自动,所以奇怪的是你看不到新对象。也许您正在为查询使用不同的事务?在这种情况下,不同的事务将永远不会看到另一个事务的未提交更改,即事务的那种点。
【讨论】:
以上是关于在提交之前不会通过查询检索持久化实体的主要内容,如果未能解决你的问题,请参考以下文章