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:
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:
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
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
Post a Comment