mise en veille prolongée, MySQL, GlassFish v3 et source de données JTA
-
23-09-2019 - |
Question
Je tente d'utiliser le gestionnaire de l'entité mise en veille prolongée avec MySQL et GlassFish. Je reçois l'erreur suivante lorsque vous tentez d'utiliser une source de données JTA:
Caused by: org.hibernate.HibernateException: The chosen transaction strategy requires access to the JTA TransactionManager
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:376)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1367)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:858)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:733)
... 37 more
Voici comment j'ai configuré mes persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" 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_1_0.xsd">
<persistence-unit name="myPU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jdbc/mysql</jta-data-source>
<class>com.my.shared.entity.MyFile</class>
<class>com.my.shared.entity.MyRole</class>
<class>com.my.shared.entity.MyUser</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show.sql" value="true" />
</properties>
Cependant, quand je configure une source de données non JTA, il fonctionne très bien
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" 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_1_0.xsd">
<persistence-unit name="myPU" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<non-jta-data-source>jdbc/mysql</non-jta-data-source>
<class>com.my.shared.entity.MyFile</class>
<class>com.my.shared.entity.MyRole</class>
<class>com.my.shared.entity.MyUser</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.show.sql" value="true" />
</properties>
</persistence-unit>
</persistence>
C'est bien beau, mais je voudrais vraiment utiliser:
em.persist(myObject);
au lieu de:
em.getTransaction().begin();
em.persist(myObject);
em.getTransaction().commit();
Suis-je manque quelque chose avec la configuration de mise en veille prolongée, ou est-il même possible d'utiliser une source de données JTA?
La solution
Il semble que pour votre configuration, les transactions gérées par le conteneur sont utilisées par défaut. Dans ce cas, vous devez définir un mode de synchronisation des transactions de sorte que la couche de persistance est notifiée (et peut mettre à jour le cache de niveau 2 par exemple). Vous devez donc définir manager_lookup_class
propriété comme suit:
// For GlassFish:
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.SunONETransactionManagerLookup
// For WebSpere:
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.WebSphereExtendedJTATransactionLookup
// For JBoss:
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
// For OpenEJB:
hibernate.transaction.manager_lookup_class=org.apache.openejb.hibernate.TransactionManagerLookup
Aussi, vous devez marquer des méthodes commerciales qui ont accès à la couche de données « transactionnel ». Pour cela, vous devez les marquer avec @javax.ejb.TransactionAttribute(REQUIRED)
(voir ici pour plus d'informations sur cette annotation).
Vous avez également la possibilité de passer à des transactions gérées par le bean. Vous pouvez le faire en disant:
hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
Alors le haricot est responsable de début / fin de la transaction:
org.hibernate.Session session = ...;
org.hibernate.Transaction tx = null;
try {
tx = session.beginTransaction();
session.createQuery(...); // do some staff
tx.commit();
} catch (HibernateException e)
{
if (tx != null) {
tx.rollback();
}
}