以下代码来自JPA规范。我不明白为什么em.joinTransaction()中需要createLineItem(int quantity)

谁能提供一个恰当的解释?

@Stateful
public class ShoppingCartImpl implements ShoppingCart {

   @PersistenceUnit
   private EntityManagerFactory emf;
   private EntityManager em;
   private Order order;
   private Product product;

   @PostConstruct
   public void init() {
      em = emf.createEntityManager();
   }

   public void initOrder(Long id) {
      order = em.find(Order.class, id);
   }

   public void initProduct(String name) {
      product = (Product) em
            .createQuery("select p from Product p where p.name = :name")
            .setParameter("name", name).getSingleResult();
   }

   public LineItem createLineItem(int quantity) {
      em.joinTransaction();
      LineItem li = new LineItem(order, product, quantity);
      order.getLineItems().add(li);
      em.persist(li);
      return li;
   }

   @Remove
   public void destroy() {
      em.close();
   }

}

最佳答案

首先,几句理论...

应用程序管理的实体管理器以两种方式之一参与JTA事务。

  • 如果在事务内部创建了持久性上下文,则持久性提供程序将自动将持久性上下文与事务同步。
  • 如果持久性上下文是较早创建的(在事务外部或已结束的事务中),则可以通过在joinTransaction()接口(interface)上调用EntityManager将持久性上下文与事务手动同步。一旦同步,持久化上下文将在事务提交时自动刷新。

  • 阅读以上定义后,可能会出现一些问题:
  • 我们如何知道ShoppingCartImpl参与了JTA事务?因为该类已使用@Stateful(或@Stateless)注释进行了注释,因此其目的是在默认使用JTA事务的Java EE环境中执行该类。如果一个类将在Java SE环境中执行,则不需要此类注释。
  • 我们如何知道在这种特殊情况下使用了应用程序管理的实体管理器?因为我们使用@PersistenceUnit批注注入(inject)EntityManagerFactory,然后手动创建和销毁EntityManager。通过这样做,我们告诉Java EE容器我们不希望自动管理事务(例如在事务范围的实体管理器或扩展的实体管理器类型的情况下)。
  • 为什么em.joinTransaction()方法中需要createLineItem?通过调用em.joinTransaction(),我们通知应用程序管理的持久性上下文它应该与当前JTA事务同步。如果没有这样的调用,则在事务提交时(在Order方法的结尾),对createLineItem的更改将不会刷新到基础数据库。注意:由于EntityManagerFactory实例是线程安全的,而EntityManager实例不是线程安全的,因此应用程序不得在多个并发事务中的同一实体管理器上调用em.joinTransaction()
  • 09-26 17:54