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。