How to use Atomikos Transaction Essentials with Hibernate >= 4.3

14.5k Views Asked by At

I switched from Hibernate 4.2 to Hibernate 4.3 and my project is not working any more. I'm getting an

HibernateException: Unable to locate current JTA transaction

when I do

Session s = sessionFactory.getCurrentSession();

I've realized that org.hibernate.transaction.TransactionManagerLookup does not exist any more. It was deleted in Hibernate 4.3. How should I change my current configuration?

<hibernate-configuration>
<session-factory>
    <property name="connection.datasource">testDS</property>

    <property name="current_session_context_class">jta</property>
    <property name="transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</property>
    <property name="transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</property>
    <property name="connection.release_mode">auto</property>
    <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

    <property name="hibernate.hbm2ddl.auto">create-drop</property>
    <property name="hibernate.show_sql">true</property>
    <mapping class="test.entities.Person" />
    <mapping class="test.entities.CreditCard" />
    <mapping class="test.entities.ExampleRevEntity" />
</session-factory>

5

There are 5 best solutions below

4
sebplorenz On

In Hibernate 4.3 the long deprecated TransactionManagerLookup got removed. Now the JTA provider must implement org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform. An abstract implementation of JTA Platform is already available within Hibernate namely org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform. Using this it is quite simple to write a JTA Platform for Atomikos:

package test;

import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;
import com.atomikos.icatch.jta.UserTransactionManager;

public class AtomikosJtaPlatform extends AbstractJtaPlatform {

  private static final long serialVersionUID = 1L;
  private UserTransactionManager utm;

  public AtomikosJtaPlatform() {
    utm = new UserTransactionManager();
  }

  @Override
  protected TransactionManager locateTransactionManager() {
    return utm;
  }

  @Override
  protected UserTransaction locateUserTransaction() {
    return utm;
  }
}

In addition the name of the platform implementation class must be added to the hibernate configuration:

<property name="hibernate.transaction.jta.platform">test.AtomikosJtaPlatform</property>
0
Torsten Krah On

Some hint for Spring users - just use this implementation if you setup stuff with the factory bean:

public class AtomikosPlatform extends AbstractJtaPlatform {

  private static final long serialVersionUID = -1L;

  @Override
  protected TransactionManager locateTransactionManager() {
    return new J2eeTransactionManager();
  }

  @Override
  protected UserTransaction locateUserTransaction() {
    return new J2eeUserTransaction();
  }

}
0
Anton Lem On

To use Hibernate JTA Platform with Spring write and compile this code

package my.domain.spring.hibernate.jta;

import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;

import org.hibernate.engine.transaction.jta.platform.internal.AbstractJtaPlatform;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.util.Assert;

@SuppressWarnings("serial")
public class SpringJtaPlatformAdapter extends AbstractJtaPlatform {

    private static TransactionManager sTransactionManager;
    private static UserTransaction sUserTransaction;


    @Override
    protected TransactionManager locateTransactionManager() {
        Assert.notNull(sTransactionManager, "TransactionManager has not been setted");
        return sTransactionManager;
    }


    @Override
    protected UserTransaction locateUserTransaction() {
        Assert.notNull(sUserTransaction, "UserTransaction has not been setted");
        return sUserTransaction;
    }


    public void setJtaTransactionManager(JtaTransactionManager jtaTransactionManager) {
        sTransactionManager = jtaTransactionManager.getTransactionManager();
        sUserTransaction = jtaTransactionManager.getUserTransaction();
    }


    public void setTransactionManager(TransactionManager transactionManager) {
        sTransactionManager = transactionManager;
    }


    public void setUserTransaction(UserTransaction userTransaction) {
        sUserTransaction = userTransaction;
    }

}

Add into your spring-configuration

  <bean id="txObjcoreManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager">
            <bean class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
                <property name="forceShutdown" value="true" />
            </bean>
        </property>
        <property name="userTransaction">
            <bean class="com.atomikos.icatch.jta.UserTransactionImp">
                <property name="transactionTimeout" value="300" />
            </bean>
        </property>
    </bean>

    <bean id="springJtaPlatformAdapter" class="my.domain.spring.hibernate.jta.SpringJtaPlatformAdapter">
        <property name="jtaTransactionManager" ref="txObjcoreManager" />
    </bean>

Don't forget to add a dependency

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        depends-on="springJtaPlatformAdapter">

And finally change a hibernate configuration like this one hibernate.transaction.jta.platform=my.domain.spring.hibernate.jta.SpringJtaPlatformAdapter

0
Po-Ting Huang On

Can you try setting the jtaTransactionManager property of org.springframework.orm.hibernate4.LocalSessionFactoryBean to Spring's JtaTransactionManager? I have similar problem but solved by this. By the way, the HibernateTemplate is back on Spring 4.0.1. Although it's not recommended, but I like to use it. It helped take care of a lot of things. (I am using Spring 4.0.5 + Hibernate 4.3.5 + Atomikos 3.9.3)

<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close" depends-on="userTransactionService">
   <property name="forceShutdown" value="true" />
</bean>

<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" depends-on="userTransactionService">
   <property name="transactionTimeout" value="180" />
</bean>

<bean id="JtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
   <property name="transactionManager" ref="atomikosTransactionManager" />
   <property name="userTransaction" ref="atomikosUserTransaction" />
   <property name="allowCustomIsolationLevels" value="true"></property>
</bean>

<bean id="rentSessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource"><ref bean="rentXADataSource" /></property>
    <property name="mappingLocations" value="classpath:com/kj/model/web/*.hbm.xml"/>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</prop>
            <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
            <prop key="hibernate.show_sql">false</prop>
            <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</prop>          
            <prop key="hibernate.cache.use_query_cache">true</prop> 
            <prop key="hibernate.cache.use_second_level_cache">true</prop>
            <prop key="hibernate.format_sql">false</prop>
            <prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
        </props>
    </property>
    <property name="jtaTransactionManager" ref="JtaTransactionManager"></property>
</bean>
0
The Gilbert Arenas Dagger On

The following is an alternative approach that works with Spring configuration. This is different from Anton's approach in that is does not rely on instance method writes to a static field (which is generally considered bad practice).

@SuppressWarnings("serial")
public class AtomikosJtaPlatform extends AbstractJtaPlatform {

    private static TransactionManager transactionManager;
    private static UserTransaction userTransaction;

    public static void factoryInit(TransactionManager transactionManager, UserTransaction userTransaction) {
        AtomikosJtaPlatform.transactionManager = transactionManager;
        AtomikosJtaPlatform.userTransaction = userTransaction;
    }

    @Override
    protected TransactionManager locateTransactionManager() {
        return transactionManager;
    }

    @Override
    protected UserTransaction locateUserTransaction() {
        return userTransaction;
    }

}

Then in Spring configuration:

    <bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init"
        destroy-method="close">
        <property name="startupTransactionService" value="false" />
        <property name="forceShutdown" value="false" />
    </bean>

    <bean id="AtomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
        <property name="transactionTimeout" value="300" />
    </bean>

    <!-- AtomikosJtaPlatform is created by Hibernate using reflection. This ensures it uses our Spring configured beans --> 
    <bean id="JtaPlatformInitializer" class="org.springframework.beans.factory.config.MethodInvokingBean">
        <property name="targetClass" value="com.mycompany.a.b.AtomikosJtaPlatform" />
        <property name="targetMethod" value="factoryInit" />
        <property name="arguments">
            <list>
                <ref bean="AtomikosTransactionManager" />
                <ref bean="AtomikosUserTransaction" />
            </list>
        </property>
    </bean>

<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="JtaPlatformInitializer">
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.transaction.jta.platform">com.mycompnay.a.b.AtomikosJtaPlatform</prop>
 ...