Hibernate, MySQL, Glassfish V3 e JTA DataSource
-
23-09-2019 - |
Pergunta
Estou tentando usar o Hibernate Entity Manager com MySQL e Glassfish. Estou recebendo o seguinte erro ao tentar usar um JTA DataSource:
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
Aqui está como eu configurei minha persistência.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>
No entanto, quando eu configuro um conjunto de dados não JTA, funciona bem
<?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>
Isso está tudo bem, mas eu realmente gostaria de usar:
em.persist(myObject);
ao invés de:
em.getTransaction().begin();
em.persist(myObject);
em.getTransaction().commit();
Estou perdendo alguma coisa com a configuração do Hibernate, ou é possível usar um conjunto de dados JTA?
Solução
Parece que, para sua configuração, as transações gerenciadas por contêineres são usadas por padrão. Nesse caso, você precisa definir uma maneira de sincronização de transações para que a camada de persistência seja notificada (e pode atualizar o cache do segundo nível, por exemplo). Então você precisa definir manager_lookup_class
propriedade como seguinte:
// 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
Além disso, você deve marcar métodos de negócios que acessassem a camada de dados como "transacional". Para isso, você precisa marcá -los com @javax.ejb.TransactionAttribute(REQUIRED)
(Vejo aqui Para mais informações sobre esta anotação).
Você também tem a opção de mudar para transações gerenciadas por feijão. Você pode fazer isso dizendo:
hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
Então o feijão é responsável por iniciar/encerrar a transação:
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();
}
}