web-dev-qa-db-fra.com

Un EntityManager JTA ne peut pas utiliser getTransaction ()

Comment puis-je avoir le code suivant dans mon application non-ejb. Le code fonctionne.

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

Dans une nouvelle application, j'utilise EJB3 + JSF et souhaite réutiliser la bibliothèque contenant le code ci-dessus. Mon unité de persistance pour la nouvelle application ressemble à ceci:

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

Ma nouvelle application lève une exception quand elle frappe cette ligne:

    EntityTransaction tx = em.getTransaction();

l'exception est:

A JTA EntityManager cannot use getTransaction()

Ce qui est assez clair. La question est de savoir comment convertir mon code pour que les transactions soient gérées par le conteneur. On peut supposer que mes méthodes de haricot doivent être annotées de manière appropriée ... La question est de savoir comment?

20
auser

EntityTransaction est utilisé avec un gestionnaire d'entités de type ressource local. Si vous souhaitez utiliser JTA, vous devez utiliser l'interface UserTransaction.

From Documentation:EntityTransaction - Interface utilisée pour contrôler les transactions sur les gestionnaires d'entités locales. La méthode EntityManager.getTransaction () renvoie l'interface EntityTransaction.


Édition: Ajout de pseudo-code.

@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 
  }
}   
15
Nayan Wadekar

Dans le cas le plus simple, cela fonctionne. Si votre EntityManager est injecté dans EJB et que vous n'utilisez pas d'annotations spéciales, la transaction s'ouvre dans la première méthode EJB entrée (cela signifie que si EjbA appelle EjbB et qu'EjbC à son tour appelle une seule transaction sera utilisée pour toutes les méthodes EJB. ). Si vous souhaitez modifier le mode de contrôle des transactions, recherchez @Transaction.

Le moyen le plus simple de faire une restauration est de lever une exception marquée avec @ApplicationException (rollback = true).

Je peux me tromper, mais à en juger par votre code, vous devriez lire la différence entre EXTENDED et NORMAL EntityManager. Il semble que vous utilisiez un em étendu de manière très délicate (déplacer la boucle en dehors de la transaction vous aiderait à vous en débarrasser enfin).

Petite modification: si vous essayez d'utiliser UserTransaction, comme le suggère l'autre message, vous obtiendrez une erreur, car un EntityManager standard (que vous utilisez probablement) utilise la procédure appelée CMT (Container Managed Transactions). Ne touchez pas cela, à moins que vous ne compreniez les trois oppositions de base (si vous voulez, je peux élaborer, mais franchement, vous n'en aurez PAS besoin):

  • entityManager géré par conteneur ou EntityManager géré par application,
  • les transactions gérées par conteneur par rapport aux transactions gérées par application,
  • NORMAL EntityManager et EXTENDED EntityManager.
5
fdreger

juste pour résumer le code qui fonctionne pour moi sur Jboss EAP6 et Hibernate 4.2.18.Final.

Peut gagner du temps pour quelqu'un.

persistence.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>

Java

 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>

liens:

Gestionnaires d'entités gérées par l'application https://docs.Oracle.com/cd/E19798-01/821-1841/bnbra/index.html

Comment UserTransaction et EntityManager interagissent-ils?

0
David Abragimov