Spring Transaction in JTA With Atomikos 2

We are going to implement JTA IN Spring to support Distributed(XA) Transactions in our Module.

The underlying JTA implementation that we will be using is Atomikos. It is Open Source.

Let's first traverse through the configuration part for implementing JTA in Spring.

The required list of jars are:

1) hibernate-core-3.6.0.Final.jar

2) transactions-jta-3.6.4.jar

3) atomikos-util-3.6.4.jar

4) transactions-3.6.4.jar

5) transactions-api-3.6.4.jar

6) transactions-hibernate3-3.6.4.jar

7) transactions-jdbc-3.6.4.jar

8) concurrent-1.3.4.jar

9) cglib-nodep-2.2.3.jar

--------------------------------------------

Config Changes of Application Context.xml

--------------------------------------------

<context:component-scan base-package="com.springRest.controllers"></context:component-scan>

<context:annotation-config></context:annotation-config>

<tx:annotation-driven transaction-manager="transactionManager"/>

The controller is annotated with @Transactional annotation so, "context:component-scan"

of the package containing the controllers are carried out so that those controllers are

picked up by BeanPostProcessors of Spring and registered in the Spring Application Context

and are made functional with the annotation i.e. "@Transactional".

The definition of the Transaction Manager is: <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" depends-on="atomikosTransactionManager,atomikosUserTransaction">

<property name="transactionManager" ref="atomikosTransactionManager" />

<property name="userTransaction" ref="atomikosUserTransaction" />

<property name="allowCustomIsolationLevels" value="true" />

</bean>



The underlying Transaction Manager and User Transaction implementation is:

a) atomikosTransactionManager

b) atomikosUserTransaction

and their definitions are: <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"

init-method="init" destroy-method="close">

<property name="forceShutdown" value="true" />

</bean>

<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">

<property name="transactionTimeout" value="3000" />

</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>



The Entity Manager being used for Persisting Domain Entity is as follows.: <bean id="entityManager" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" abstract="true">

<property name="jpaVendorAdapter">

<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">

<!-- property name="showSql" value="true" />

<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" /-->

</bean>

</property>

<property name="packagesToScan" value="com.springRest.domainEntity"></property>

<property name="jpaProperties">

<props>

<prop

key="hibernate.transaction.manager_lookup_class">com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup</prop>

<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>

<prop key="hibernate.max_fetch_depth">3</prop>

<prop key="hibernate.jdbc.fetch_size">50</prop>

<prop key="hibernate.jdbc.batch_size">10</prop>

<prop key="hibernate.show_sql">true</prop>

<!-- prop key="hibernate.format_sql">true</prop-->

<!-- prop key="hibernate.current_session_context_class">jta</prop-->

<prop key="javax.persistence.transactionType">jta</prop>

</props>

</property>

</bean>



The Transaction template being used to avoid all broilerplate code and the bean definition is: <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">

<property name="propagationBehavior" value="0"></property>

<property name="timeout" value="10"></property>

<property name="transactionManager" ref="transactionManager"></property>

</bean>



The transactionTemplate is used to encapsulate a particular set of operations within

a single transaction using callbacks. For example:
   
   String ok2 = transactionTemplate.execute(new TransactionCallback<String>() {
    String ok;
   public String doInTransaction(TransactionStatus transactionStatus)
   {
    ok = insertCarEntry();
    return ok;
    
   }
   
  });
  
  


TransactionTemplate is the programmatic approach of implementing Transaction in Spring.

The other approach is Annotation based approach i.e. @Transaction, which we will be using throughout.

The Entity Manager Factory for JPA related configurations is: <bean id="emfA" parent="entityManager">

<property name="dataSource" ref="dataSourceBean"></property>

</bean>



In bean configuration below, the EntityManger and the Transaction manager is

used by the bean post processors after scanning the repository

classes in the base package and registering them in the

application Context as described by the jpa namespaces. <jpa:repositories base-package="com.springRest.repo.repository" entity-manager-factory-ref="emfA" transaction-manager-ref="transactionManager" factory-class="com.springRest.config.repository.SpringrestRepositoryFactoryBean" >



The XA Data Source is configured in jBoss(AS 7) in standalone.xml as <datasources>

<xa-datasource jta="true" jndi-name="java:jboss/datasources/XADBMSA" pool-name="XADBMSA" enabled="true" use-java-context="true" use-ccm="true">

<xa-datasource-property name="URL">

jdbc:oracle:thin:@localhost:1521:XE </xa-datasource-property>

<xa-datasource-property name="User">

SYSTEM </xa-datasource-property>

<xa-datasource-property name="Password">

admin </xa-datasource-property>

<xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>

<driver>oracle</driver>

</xa-datasource>

<drivers>

<driver name="oracle" module="oracle.jdbc">

<driver-class>oracle.jdbc.OracleDriver</driver-class>

<xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>

</driver>

</drivers>

</datasources>



----------------------------------------------------------

XA DataSourceBean bean config

-------------------------------------------------------------

<bean id="dataSourceBean" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">

<property name="uniqueResourceName"><value>java:jboss/datasources/XADBMSA</value></property>

<property name="xaDataSourceClassName"><value>oracle.jdbc.xa.client.OracleXADataSource</value></property>

<property name="xaProperties">

<props>

<prop key="databaseName">XE</prop>

<prop key="user">SYSTEM</prop>

<prop key="password">admin</prop>

<prop key="URL">jdbc:oracle:thin:@localhost:1521:XE</prop>

</props>

</property>

<property name="minPoolSize"><value>1</value></property>

<property name="maxPoolSize"><value>20</value></property>

</bean>



:::: An XA datasource has already been configured in Jboss with the UniqueName

-------------------------------------------------------------------------------------------

jBoss-Deployment-Structure.xml

-------------------------------------------------------------------------------------------

<?xml version="1.0" encoding="UTF-8"?>

<jboss-deployment-structure>

<deployment>

<dependencies>

<module name="org.hibernate" />

<module name="org.hibernate.envers" />

<module name="org.hibernate.validator" />

</dependencies>

</deployment>

</jboss-deployment-structure>



::::: This is being used to pre deploy the already existing Module with

jBoss with dependencies tag or to exclude them using exclusions tag

The Demo Code being used here is:
 
 @Transactional
 public ModelAndView insertCarEntryNew() throws Exception
 {
   
  /*String ok2 = transactionTemplate.execute(new TransactionCallback<String>() {
    String ok;
   public String doInTransaction(TransactionStatus transactionStatus)
   {
    ok = insertCarEntry();
    return ok;
    
   }
   
  });*/
  
  
  
  
  String ok2 = insertCarEntry();
  
  myLogger.log(ILoggerLevel.DEBUG, " *** The value of ok2 is:"+ok2);
  return new ModelAndView(ok2);
  
 }
 
 
 
 @Transactional(propagation=Propagation.REQUIRED/*,rollbackFor={Exception.class,RuntimeException.class}*/)
 @RequestMapping(value="/insertCarEntry" ,method=RequestMethod.GET)
 public String insertCarEntry() throws Exception
 {
  //myLogger.log(ILoggerLevel.DEBUG, " The JNDI TRAN MANAGER IS:"+(TransactionManager) new InitialContext().lookup("java:jboss/TransactionManager"));

  
  // Dummy value for Testing
  
  int x = 1;
  
  // To be removed after Testing
  
  
   
  Car car = new Car();
  car.setAge(4);
  car.setLicensePlate("AUDI A8");
  car.setManufactureDate(new Date());
  car.setManufacturer("AUDI");
  //car.setVersion(3);
   car = carService.save(car);
  
  myLogger.log(ILoggerLevel.DEBUG, " *** The car thus saved is OK 999---->"+car);
  
  
  
  
  /*myLogger.log(ILoggerLevel.DEBUG, " The Entity manager is:"+em);
  em.persist(car);
  em.flush();*/
  
  
  if( x == 1)
   throw new Exception(" Please Explicitly rollback Exception 999" );
  
  
  return "abc"
  
  }

  
  


In the above code at first insertCarEntryNew() is called which in turn calls up insertCarEntry().

In insertCarEntry() an instance of Car object is created and is persisted

with the service layer save() method.

Then an exception is thrown explicitly to rollback the whole transaction ,i.e.

to rollback all the work that has been performed till now as an exceptio is

being raised in the current running transaction.

Thus the transaction started in insertCarEntryNew() is carried forward to the

called method i.e. insertCarEntry(). This is done through @Transaction annotation

and the propogation strategy which is Required in this case.

This is in short JTA implementation in Spring for distributed transactions.

New queries and suggestions are always welcome. Please do send them as

they acts as encouragement and till then happy coding

Comments

Popular posts from this blog

Use of @Configurable annotation.

Spring WS - Part 5

Spring WS - Part 4