Hibernate、MySQL、GlassFish V3 和 JTA 数据源

8

我正在尝试使用Hibernate实体管理器与MySQL和Glassfish。当尝试使用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

这是我配置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>

然而,当我配置一个非JTA数据源时,它可以正常工作。

<?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>

这很好,但我真的想使用:

em.persist(myObject);

改为:

em.getTransaction().begin();
em.persist(myObject);
em.getTransaction().commit();

我对Hibernate配置是否缺少了什么,或者是否可以使用JTA数据源有疑问。
1个回答

12

看起来在您的配置中,默认使用容器管理的事务。在这种情况下,您需要定义一种事务同步的方式,以便通知持久层(并可以更新第二级缓存)。因此,您需要按以下方式定义manager_lookup_class属性:

// 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
此外,您还需要将访问数据层的业务方法标记为"transactional"。为此,您需要使用@javax.ejb.TransactionAttribute(REQUIRED)注释对它们进行标记(有关此注释的详细信息,请参见此处)。
您还可以选择切换到Bean-managed事务。您可以通过以下方式实现: hibernate.transaction.factory_class=org.hibernate.transaction.JTATransactionFactory 然后,bean负责开始/结束事务:
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();
    }
}

2
好的,所以我在我的persistence.xml中添加了<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.SunONETransactionManagerLookup" />。现在它可以“持久化”而没有错误,但是它从未提交到数据库。 - KevMo
@KevMo:你不需要像 em.getTransaction().begin(); 那样声明性地启动一个事务,因为你正在使用 CMT。希望你已经在你的 Bean 方法上标记了 @Transactional - dma_k
抱歉,看来您没有使用Spring :) 请按照我的答案操作。 - dma_k

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接