24

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

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

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

  <persistence-unit name="myApp" transaction-type="JTA">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <jta-data-source>MySQLConnection</jta-data-source>
  </persistence-unit>

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

    EntityTransaction tx = em.getTransaction();

例外是:

A JTA EntityManager cannot use getTransaction()

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

4

4 回答 4

17

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

来自文档: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 
  }
}   
于 2012-06-10T09:22:43.373 回答
5

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

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

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

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

  • 容器管理的 EntityManager 与应用程序管理的 EntityManager,
  • 容器管理事务与应用程序管理事务,
  • 普通实体管理器和扩展实体管理器。
于 2012-06-10T08:10:31.497 回答
2

只是总结一下在 Jboss EAP6 和 Hibernate 4.2.18.Final 上对我有用的代码。

可以为某人节省时间。

持久性.xml

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
         version="2.0">
<persistence-unit name="myApp" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/MySQLConnection</jta-data-source>
<properties>
        <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
        <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
        <!--
        <property name="hibernate.show_sql" value="true" />
        -->
    </properties>
</persistence-unit>

爪哇

 import javax.annotation.Resource;
 import javax.persistence.EntityManager;
 import javax.transaction.UserTransaction;

public class MyClass {
@PersistenceContext(unitName = "myApp")
protected EntityManager em;
@Resource
UserTransaction utx;

public void execute(..) throws Exception {
    try {
        utx.begin();
        em.remove(..);
        em.merge(..);
        em.persist(..);
        utx.commit();
    } catch (Exception ex) {
        try {
            utx.rollback();
        } catch (Exception re) {
            throw new RollbackFailureException("An error occurred attempting to roll back the transaction.", re);
        }
        throw ex;
    }
}

}

pom.xml

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
        <scope>provided</scope>
    </dependency>

链接:

应用程序管理的实体管理器https://docs.oracle.com/cd/E19798-01/821-1841/bnbra/index.html

UserTransaction 和 EntityManager 是如何交互的?

于 2018-12-28T23:00:22.553 回答
1

“可以为某人节省时间。”

它确实节省了我的时间!我希望我能在几天前​​找到您的解决方案。我一直在努力解决如何在 JTA 持久性单元的上下文中处理 bean 管理的事务。我们的大部分使用只是一个 bean 方法中的一次 JPA DML 调用。问题是在执行单个 DML 操作后,对存储过程的后续调用(在同一 bean 方法中)将失败,抱怨无法在正在运行的事务中启动另一个事务。文档详尽但繁琐。

这是关键:@Resource UserTransaction utx;

谢谢!

于 2021-03-20T07:39:59.407 回答