为什么我们必须在扩展的PersistenceContext中手动flush()EntityManager?

时间:2011-09-01 15:08:36

标签: java jpa persistence ejb flush

在我们的J2EE应用程序中,我们使用EJB-3有状态bean来允许前端代码创建,修改和保存持久性实体(通过JPA-2管理)。

它看起来像这样:

@LocalBean
@Stateful
@TransactionAttribute(TransactionAttributeType.NEVER)
public class MyEntityController implements Serializable
{   
    @PersistenceContext(type = PersistenceContextType.EXTENDED)
    private EntityManager em;

    private MyEntity current;

    public void create()
    {
        this.current = new MyEntity();
        em.persist(this.current);
    }

    public void load(Long id)
    {
        this.current = em.find(MyEntity.class, id);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void save()
    {
        em.flush();
    }
}

非常重要的是,为了避免过早提交,只有save()方法在一个事务中,所以如果我们调用create(),我们就不会在数据库中插入任何内容。

奇怪的是,在save()方法中,我们必须调用em.flush()才能真正命中数据库。事实上,我尝试过发现我们也可以调用em.isOpen()em.getFlushMode(),以及任何与“em相关”的内容。

我不明白这一点。由于save()在事务中,我认为在方法结束时,事务将被提交,因此持久性实体管理器会自动刷新。为什么我必须手动冲洗它?

谢谢, 泽维尔

3 个答案:

答案 0 :(得分:7)

要直接使用金属,在您 事务中

我们在app-server-land中将创建其中一个对象来执行javax.transaction.Synchronization并将其注册到flush()javax.transaction.TransactionSynchronizationRegistry。除非存在活动交易,否则无法执行此操作。

这就是它的长短。

是的,应用服务器可以很好地保留它给有状态bean的资源列表,并在有状态bean可能启动或参与的每个事务中自动注册它们。缺点是你完全失去了决定的能力哪些事情在哪些交易中进行。也许你有两个或三个不同的事务在不同的持久性单元上运行,并且在一个非常特定的事务中聚合扩展持久化上下文中的工作。这确实是一个设计问题,应用服务器应该将此类决定留给应用程序本身。

您在交易中使用它,我们会将其注册到交易中。这是基本合同。

附注,根据底层EntityManager的处理方式,对EntityManager 的任何持久调用可能足以在事务结束时导致完全刷新。当然,javax.transaction.Transaction是最直接和最明确的,但flush()甚至persist()可能会这样做。

答案 1 :(得分:0)

如果使用扩展持久性上下文,则在非事务性方法内完成的对托管实体的所有操作都将排队等待写入数据库。在事务上下文中对实体管理器调用flush()后,所有排队的更改都将写入数据库。换句话说,当有方法退出时(如在CMT中),事务方法不会提交事务方法,但实际管理器管理器实际上是这样做的。您可以找到此过程的完整说明here

答案 2 :(得分:0)

因为没有办法知道“何时”客户端完成了会话(扩展范围)。