How to use Atomikos Transaction Essentials with Hibernate >= 4.3
Asked Answered
C

5

11

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>

Cant answered 19/12, 2013 at 11:59 Comment(0)
C
7

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>
Cant answered 19/12, 2013 at 12:12 Comment(4)
Great answer! I was fighting this for a day and a half. Do you know if there is a way in Spring to use my previously defined transactionManager and userTransaction beans instead of creating a new one here?Outland
Hi Eric, the problem is that Hibernate will create a new instance of the JTA platform at startup. There is no way to inject a Spring created JTA platform with its Spring created transaction manager into Hibernate (AFAIK). What you could do is make the references to the user transaction and the transaction manager static in the JTA Platform. Then create it all in the Spring context before Hibernate makes first use of the JTA platform.Cant
I got around the spring injection problem by creating a Class that implements the ApplicationContextAware interface to provide the appCtx and change the AtomikosJtaPlatform class to fetch the UserTransaction from the spring context each time : @Override protected TransactionManager locateTransactionManager() { return SpringContext.getApplicationContext().getBean("atomikosTransactionManager", UserTransactionManager.class); }Prepare
I am trying to use atomikos tm for jbpm runtime engine. I have implemented custom platform implementation and updated hibernate platform entry in persistance.xml but i am getting below exception - Caused by: javax.persistence.TransactionRequiredException: Explicitly joining a JTA transaction requires a JTA transaction be currently active at org.hibernate.internal.SessionImpl.joinTransaction(SessionImpl.java:3766) at org.hibernate.internal.SessionImpl.joinTransaction(SessionImpl.java:3751)Wardwarde
L
6

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

Learn answered 10/2, 2014 at 11:54 Comment(0)
M
2

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();
  }

}
Massif answered 17/1, 2014 at 16:29 Comment(0)
S
1

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>
Shreeves answered 8/7, 2014 at 9:4 Comment(0)
P
0

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>
 ...
Panegyric answered 7/3, 2018 at 15:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.