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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7272354/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 19:22:31  来源:igfitidea点击:

Why do we have to manually flush() the EntityManager in a extended PersistenceContext?

javajpapersistenceejbflush

提问by Xavier Portebois

In our J2EE application, we use a EJB-3 stateful bean to allow the front code to create, modify and save persistent entities (managed through JPA-2).

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

It looks something like this:

它看起来像这样:

@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();
    }
}

Very important, to avoid too early commits, only the save()method is within a transaction, so if we call create(), we insert nothing in the database.

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

Curiously, in the save()method, we have to call em.flush()in order to really hit the database. In fact, I tried and found that we can also call em.isOpen()or em.getFlushMode(), well anything that is "em-related".

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

I don't understand this point. As save()is in a transaction, I thought that at the end of the method, the transaction will be committed, and so the persistent entity manager automatically flushed. Why do I have to manually flush it?

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

Thanks, Xavier

谢谢,泽维尔

采纳答案by David Blevins

To be direct and to the metal, there will be no javax.transaction.Synchronizationobjects registered for the EntityManager in question until you actually useit ina transaction.

为了直接和金属,javax.transaction.Synchronization在您实际事务中使用它之前,不会为有问题的 EntityManager 注册任何对象。

We in app-server-land will create one of these objects to do the flush()and register it with the javax.transaction.TransactionSynchronizationRegistryor javax.transaction.Transaction. This can't be done unless there is an active transaction.

我们在 app-server-land 中将创建这些对象之一来执行flush()并使用javax.transaction.TransactionSynchronizationRegistryor注册它javax.transaction.Transaction。除非有活动事务,否则无法执行此操作。

That's the long and short of it.

这就是它的长处和短处。

Yes, an app server could very well keep a list of resources it gave the stateful bean and auto-enroll them in every transaction that stateful bean might start or participate in. The downside of that is you completely lose the ability to decide which things go in which transactions. Maybe you have a 2 or 3 different transactions to run on different persistence units and are aggregating the work up in your Extended persistence context for a very specific transaction. It's really a design issue and the app server should leave such decisions to the app itself.

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

You use it in a transaction and we'll enroll it in the transaction. That's the basic contract.

您在交易中使用它,我们将在交易中注册它。这就是基本的契约。

Side note, depending on how the underlying EntityManager is handled, anypersistent call to the EntityManager maybe enough to cause a complete flush at the end of the transaction. Certainly, flush()is the most direct and clear but a persist()or even a find()might do it.

旁注,根据底层 EntityManager 的处理方式,对 EntityManager 的任何持久调用可能足以在事务结束时导致完全刷新。当然,flush()是最直接明了的,但是一个persist()甚至一个都find()可以做到。

回答by Ravindranath Akila

Because there is no way to know "when" the client is done with the session (extended scope).

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

回答by Kris

If you use extended persistence context all operations on managed entities done inside non-transactional methods are queued to be written to the database. Once you call flush() on entity manager within a transaction context all queued changes are written to the database. So in other words, the fact that you have a transactional method doesn't commit the changes itself when method exits (as in CMT), but flushing entity manager actually does. You can find full explanation of this process here

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