2011-09-01 114 views
9

在我们的J2EE应用程序中,我们使用EJB-3有状态bean来允许前端代码创建,修改和保存持久实体(通过JPA-2进行管理)。为什么我们必须在扩展的PersistenceContext中手动刷新()EntityManager?

它看起来是这样的:

@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(),以及任何与“时间相关”的东西。

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

感谢, 泽维尔

+0

不需要'flush()'。 'joinTransaction()'应该足以在你的事务性方法中保存你的修改。 –

回答

7

的完整解释是直接和金属,将会在交易受到质疑注册了EntityManager没有对象,直到你真正使用

我们在app-server-land将创建这些对象中的一个来执行flush()并将其注册为javax.transaction.TransactionSynchronizationRegistryjavax.transaction.Transaction。除非存在活动事务,否则无法完成此操作。

这就是它的长与短。

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

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

侧面说明,这取决于底层的EntityManager是如何处理的,到了EntityManager 任何持续通话可足以在交易结束时导致完全齐平。当然,flush()是最直接和最清楚的,但persist()甚至可能是find()

+1

Wooh,我花了一些时间来完全理解你的答案,但现在它是有道理的。谢谢!从JPA2.1说明书 –

+0

相关报价(用于持久性上下文传播7.6.4.1要求)的非传播性 持久上下文:'如果实体管理器被一个JTA事务中调用的,持久性上下文将 可以与JTA交易相关联'。 –

0

如果您使用扩展的持久化上下文里面非事务方法进行管理的实体所有的操作都排队等待写入到数据库。一旦在事务上下文中的实体管理器上调用flush(),所有排队的更改都将写入数据库。换句话说,事实上你有一个事务性方法,当方法退出时(如在CMT中),本身并不提交这些改变,但是实际上冲掉实体管理器。你可以找到这个过程here

+2

我看了本教程,但似乎有点混淆。 它表示“这意味着您调用的任何持久化,合并或移除方法实际上都不会导致JDBC执行,因此在您手动调用EntityManager.flush之前更新数据库。”指向你:) 但在第二个例子中,它说“never()更新将在checkout()方法结束时提交”,并且此checkout()是空的,没有任何刷新。你怎么能解释这个例子? 另外,在Adam Bien的Real World JavaEE Patterns中,GateWay模式也有一个空的保存方法:http://tinyurl.com/3o96xoh(幻灯片67)。 –

0

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

相关问题