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?
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
}
}
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):
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