【问题标题】: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;
    }
 }

在此示例中需要指出的一些重要事项:

  1. 调用persistEntity() 方法时没有开始交易, 因为 bean 级别的 @TransactionAttribute(NOT_SUPPORTED) 环境。
  2. 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 的要求太多了,以确定是否有任何此类挂起的实体与查询结果匹配,如果匹配则包括它们。

标签: caching jpa ejb


【解决方案1】:

您可以在提交之前调用flush()将更改写入数据库。

见,http://en.wikibooks.org/wiki/Java_Persistence/Persisting#Flush

EntityManager 上还有一个刷新模式,它将在每次查询之前触发刷新,默认为自动,所以奇怪的是你看不到新对象。也许您正在为查询使用不同的事务?在这种情况下,不同的事务将永远不会看到另一个事务的未提交更改,即事务的那种点。

【讨论】:

    猜你喜欢
    • 2011-01-11
    • 2011-12-23
    • 2013-08-13
    • 2014-02-10
    • 2019-10-20
    • 2014-11-22
    • 2012-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多