JTA EntityManager无法使用getTransaction()

如何在我的非ejb应用程序中使用以下代码。 代码有效。

@Override public void saveItems(Collection items) { synchronized (em) { EntityTransaction tx = em.getTransaction(); try { tx.begin(); for (T item : items) { saveItem_((Class) null, item); } tx.commit(); } finally { if (tx.isActive()) { tx.rollback(); } } } } 

在一个新的应用程序中,我正在使用EJB3 + JSF,并希望重用包含上述代码的库。 我对新应用程序的持久性单元如下所示:

   org.hibernate.ejb.HibernatePersistence MySQLConnection  

我的新应用程序在遇到此行时抛出exception:

  EntityTransaction tx = em.getTransaction(); 

例外是:

 A JTA EntityManager cannot use getTransaction() 

这很清楚。 问题是如何转换我的代码以使容器管理的事务。 大概我的bean方法需要适当注释……问题是如何?

EntityTransaction与资源本地类型的实体管理器EntityTransaction使用。 如果要使用JTA,则必须使用UserTransaction接口。

From Documentation: EntityTransaction – 用于控制资源本地实体管理器上的事务的接口。 EntityManager.getTransaction()方法返回EntityTransaction接口。


编辑:添加了伪代码。

 @Resource private SessionContext sessionContext; void execute(){ UserTransaction userTxn = sessionContext.getUserTransaction(); try{ userTxn.begin(); /** * do-something */ userTxn.commit(); } catch(Throwable e){ userTxn.rollback(); //-- Include this in try-catch } } 

在最简单的情况下 – 它只是有效。 如果您将EntityManager注入EJB并且不使用特殊注释,则事务将在输入的第一个EJB方法中打开(这意味着如果EjbA调用EjbB并且反过来调用EjbC,则所有EJB方法中将只使用一个事务)。 如果要修改事务的控制方式,请查找@Transaction。

执行回滚的最简单方法是抛出标有@ApplicationException的exception(rollback = true)

我可能错了,但从你的代码判断你应该阅读EXTENDED和NORMAL EntityManager之间的区别。 看起来你正在以非常尴尬的方式使用扩展的em(将循环移出事务将帮助你最终摆脱)。

小编辑:如果您尝试使用UserTransaction,正如另一篇文章建议的那样,您将收到错误,因为标准的EntityManager(您可能正在使用)使用所谓的CMT(容器管理事务)。 不要触摸它,除非你理解三个基本的选择(如果你愿意,我可以详细说明,但坦率地说,你不需要它):

  • 容器管理的EntityManager与应用程序管理的EntityManager,
  • 容器管理事务与应用程序管理事务,
  • NORMAL EntityManager和EXTENDED EntityManager。