In this tutorial we shall show you how to implement JTA multiple resource transactions in a Tomcat server, using Atomikos Transaction Manager. Atomicos transaction manager provides support for distributed transactions. These are multi-phased transactions, often using multiple databases, that must be committed in a coordinated way. The distributed transactions are described by the XA standard. XA governs how a transaction manager (such as Atomikos) can tell a database what work is going on as part of what transaction, and how to conduct the two-phase commit (2PC) protocol at the end of each transaction.
Here, we will create simple
Entity
classes mapped to two different databases and we will try to persist objects of the classes to the databases using one distributed transaction. We will also see what happens when one of the underlying transactions rollbacks.
Our preferred development environment is Eclipse. We are using Eclipse Juno (4.2) version, along with Maven Integration plugin version 3.1.0.We are also using Spring version 3.2.3 and the JDK 7_u_21.
Tomcat 7 is the application server used. Hibernate version is 4.1.9, and the database used in the example is MySQL Database Server 5.6.
Let’s begin,
1. Create a new Maven project
Go to
File
->
Project
->
Maven
->
Maven Project
.
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICMxkTM0gTN5AzMwkDM1EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
In the “Select project name and location” page of the wizard, make sure that “Create a simple project (skip archetype selection)” option is unchecked, hit “
Next
” to continue with default values.
Here the maven archetype for creating a web application must be added. Click on “Add Archetype” and add the archetype. Set the “Archetype Group Id” variable to “org.apache.maven.archetypes”, the “Archetype artifact Id” variable to “maven-archetype-webapp” and the “Archetype Version” to “1.0”. Click on “OK” to continue.
In the “Enter an artifact id” page of the wizard, you can define the name and main package of your project. Set the “Group Id” variable to “com.javacodegeeks.snippets.enterprise
" and the “Artifact Id” variable to "
springexample`”. The aforementioned selections compose the main project package as “com.javacodegeeks.snippets.enterprise.springexample” and the project name as “springexample”. Set the “Package” variable to “war”, so that a war file will be created to be deployed to tomcat server. Hit “Finish” to exit the wizard and to create your project.
The Maven project structure is shown below:
It consists of the following folders:
-
folder, that contains source files for the dynamic content of the application,/src/main/java
-
folder contains all source files for unit tests,/src/test/java
-
folder contains configurations files,/src/main/resources
-
folder contains the compiled and packaged deliverables,/target
-
folder contains the deployment descriptors for the Web application ,/src/main/resources/webapp/WEB-INF
- the
is the project object model (POM) file. The single file that contains all project related configuration.pom.xml
2. Add Spring 3.2.3 dependency
-
Locate the “Properties” section at the “Overview” page of the POM editor and perform the following changes:
Create a new property with name
and valueorg.springframework.version
.3.2.3.RELEASE
-
Navigate to the “Dependencies” page of the POM editor and create the following dependencies (you should fill the “GroupId”, “Artifact Id” and “Version” fields of the “Dependency Details” section at that page):
Group Id :
Artifact Id :org.springframework
Version :spring-web
${org.springframework.version}
Alternatively, you can add the Spring dependencies in Maven’s
pom.xml
file, by directly editing it at the “
Pom.xml
” page of the POM editor, as shown below:
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0"; xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javacodegeeks.snippets.enterprise</groupId>
<artifactId>springexample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
<properties>
<spring.version>3.2.3.RELEASE</spring.version>
</properties>
</project>
As you can see Maven manages library dependencies declaratively. A local repository is created (by default under
{user_home}/.m2
folder) and all required libraries are downloaded and placed there from public repositories. Furthermore intra – library dependencies are automatically resolved and manipulated.
3. Add all required dependencies
All dependencies needed to set up atomicos transaction manager are set here.
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javacodegeeks.snippets.enterprise</groupId>
<artifactId>springexample</artifactId>
<packaging>war</packaging>
<version>0.0.1</version>
<name>springexample Maven Webapp</name>
<url>http://maven.apache.org</url>
<build>
<finalName>springexample</finalName>
</build>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate.version}</version>
<exclusions>
<exclusion>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</exclusion>
<exclusion>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jta</artifactId>
<version>${atomikos.version}</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>${atomikos.version}</version>
</dependency>
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-hibernate3</artifactId>
<version>${atomikos.version}</version>
<exclusions>
<exclusion>
<artifactId>hibernate</artifactId>
<groupId>org.hibernate</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
</dependencies>
<properties>
<spring.version>3.2.3.RELEASE</spring.version>
<hibernate.version>4.1.9.Final</hibernate.version>
<atomikos.version>3.8.0</atomikos.version>
</properties>
</project>
4. Create the Entity classes
EmployeeA.java
and
EmployeeB.java
are the Entity classes. They use the
javax.persistence
annotations to be mapped to a table,
EMPLOYEEA
and
EMPLOYEEB
in different databases. In particular, the
@Entity
annotation specifies that each class is an entity. The
@Table
annotation specifies the primary table for the annotated entity. The
@Column
annotation is used to specify a mapped column for the persistent field, whereas the
@Id
annotation specifies the primary key field of each entity.
EmployeeA.java
package com.javacodegeeks.snippets.enterprise.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "EMPLOYEEA")
public class EmployeeA {
@Id
@Column(name = "ID", nullable = false)
private String id;
@Column(name = "NAME", nullable = false)
private String name;
@Column(name = "AGE", nullable = false)
private long age;
public EmployeeA() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getAge() {
return age;
}
public void setAge(long age) {
this.age = age;
}
}
EmployeeB.java
package com.javacodegeeks.snippets.enterprise.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "EMPLOYEEB")
public class EmployeeB {
@Id
@Column(name = "ID", nullable = false)
private String id;
@Column(name = "NAME", nullable = false)
private String name;
@Column(name = "AGE", nullable = false)
private long age;
public EmployeeB() {
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getAge() {
return age;
}
public void setAge(long age) {
this.age = age;
}
}
5. Create the DAO classes
The Data Access Obejcts implemented are the
EmployeeADAOImpl.java
and
EmployeeBDAOImpl.java
classes. They are annotated with the
@Service
annotation, dictating that they are Spring Beans and thus allowing Spring to auto-detect them. They both use the
javax.persistence.EntityManager
to interact with the databases.
An
EntityManager
instance is associated with a persistence context. A persistence context is a set of entity instances in which for any persistent entity identity there is a unique entity instance. Within the persistence context, the entity instances and their lifecycle are managed. The
EntityManager
API is used to create and remove persistent entity instances, to find entities by their primary key, and to query over entities. The
EntityManager
is configured in
persistence.xml
file, that is described in paragraph 8.1.
The set of entities that can be managed by a given
EntityManager
instance is defined by a persistence unit. A persistence unit defines the set of all classes that are related or grouped by the application, and which must be colocated in their mapping to a single database.
The
EntityManager
is injected in each DAO with the
@PersistenceContext
annotation, where the name of each persistence unit is set, as defined in the
persistence.xml
file.
A basic persist method is implemented in both DAOs, using the persist(Object entity) API method of
EntityManager
to create an object to the database.
The DAOs and their interfaces are shown below:
EmployeeADAO.java
package com.javacodegeeks.snippets.enterprise.dao;
import com.javacodegeeks.snippets.enterprise.model.EmployeeA;
public interface EmployeeADAO {
void persistEmployee(EmployeeA employee);
}
EmployeeADAO Impl.java
package com.javacodegeeks.snippets.enterprise.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Service;
import com.javacodegeeks.snippets.enterprise.model.EmployeeA;
@Service
public class EmployeeADAOImpl implements EmployeeADAO {
@PersistenceContext(unitName="PersistenceUnitA")
private EntityManager entityManager;
public void persistEmployee(EmployeeA employee) {
entityManager.persist(employee);
}
}
EmployeeBDAO .java
package com.javacodegeeks.snippets.enterprise.dao;
import com.javacodegeeks.snippets.enterprise.model.EmployeeB;
public interface EmployeeBDAO {
void persistEmployee(EmployeeB employee) throws Exception;
}
EmployeeBDAO Impl.java
package com.javacodegeeks.snippets.enterprise.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Service;
import com.javacodegeeks.snippets.enterprise.model.EmployeeB;
@Service
public class EmployeeBDAOImpl implements EmployeeBDAO {
@PersistenceContext(unitName="PersistenceUnitB")
private EntityManager entityManager;
public void persistEmployee(EmployeeB employee) throws Exception {
entityManager.persist(employee);
// throw new Exception();
}
}
6. Create the Service class
The
EmployeeADAOImpl.java
and
EmployeeBDAOImpl.java
classes are injected in the
EmployeeServiceImpl.java
class. Thus, in the
persistEmployees(EmployeeA employeeA, EmployeeB employeeB)
method implemented here, the DAOs’ methods are invoked to perform the basic interaction with the database. The
EmployeeServiceImpl.java
class is also annotated with the
@Service
annotation, dictating that it is a Spring Bean and thus allowing Spring to auto-detect it.
The
@Transactional
annotation is placed before the method, to denote that a transaction is created when the method is invoked. The transaction is a global container managed transaction and will be configured in Spring configuration file.
EmployeeService.java
package com.javacodegeeks.snippets.enterprise.service;
import com.javacodegeeks.snippets.enterprise.model.EmployeeA;
import com.javacodegeeks.snippets.enterprise.model.EmployeeB;
public interface EmployeeService {
void persistEmployees(EmployeeA employeeA, EmployeeB employeeB) throws Exception;
}
EmployeeServiceImpl.java
package com.javacodegeeks.snippets.enterprise.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.javacodegeeks.snippets.enterprise.dao.EmployeeADAO;
import com.javacodegeeks.snippets.enterprise.dao.EmployeeBDAO;
import com.javacodegeeks.snippets.enterprise.model.EmployeeA;
import com.javacodegeeks.snippets.enterprise.model.EmployeeB;
@Service("employeeService")
public class EmployeeServiceImpl implements EmployeeService{
@Autowired
EmployeeADAO employeeADAO;
@Autowired
EmployeeBDAO employeeBDAO;
@Transactional(rollbackFor=Exception.class)
public void persistEmployees(EmployeeA employeeA, EmployeeB employeeB) throws Exception {
System.out.println("Persist A");
employeeADAO.persistEmployee(employeeA);
System.out.println("Persist A OK - persist B");
employeeBDAO.persistEmployee(employeeB);
System.out.println("Persist B okk");
}
}
7. Create a servlet to run the application
The
AppServlet.java
class is a simple servlet, that implements the
org.springframework.web.HttpRequestHandler
and overrides its
handleRequest(HttpServletRequest req, HttpServletResponse resp)
API method. The
EmployeeService
is injected here, via the
@Autowire
annotation. It is used in the
handleRequest(HttpServletRequest req, HttpServletResponse resp)
API method to persist a new
EmployeeA
and a new
EmployeeB
object. The method also returns a success message if the method returns succesfully and rollback message if the method throws an exception.
AppServlet.java
package com.javacodegeeks.snippets.enterprise.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.HttpRequestHandler;
import com.javacodegeeks.snippets.enterprise.model.EmployeeA;
import com.javacodegeeks.snippets.enterprise.model.EmployeeB;
import com.javacodegeeks.snippets.enterprise.service.EmployeeService;
@Component("appServlet")
public class AppServlet implements HttpRequestHandler {
@Autowired
private EmployeeService employeeService;
public void handleRequest(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
EmployeeA em1 = new EmployeeA();
em1.setId("123");
em1.setName("John");
em1.setAge();
EmployeeB em2 = new EmployeeB();
em2.setId("123");
em2.setName("Mary");
em2.setAge();
try {
employeeService.persistEmployees(em1, em2);
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Java Code Geeks </h1>");
out.println("<h2>Both employees are inserted!</h2>");
out.println("</body>");
out.println("</html>");
} catch (Exception e) {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.println("<html>");
out.println("<head>");
out.println("<title>Hello World!</title>");
out.println("</head>");
out.println("<body>");
out.println("<h1>Java Code Geeks </h1>");
out.println("<h2>Transaction Rollback!</h2>");
out.println("</body>");
out.println("</html>");
e.printStackTrace();
}
}
}
8. Configure the application
8.1 Configure the persistence units
As mentioned above, the entityManager and the persistence unit associated with it for every database is configured in
persistence.xml
file. Here we define two persistence units. In every persistence-unit element, we define the entity class associated to the persistence-unit. The
hibernate.transaction.manager_lookup_class
property is set to
com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
. The
hibernate.transaction.factory_class
property is set to
org.hibernate.transaction.CMTTransactionFactory
.
persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
<persistence-unit name="PersistenceUnitA" transaction-type="JTA">
<class>com.javacodegeeks.snippets.enterprise.model.EmployeeA</class>
<properties>
<property name="hibernate.transaction.manager_lookup_class"
value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />
<property name="hibernate.transaction.factory_class"
value="org.hibernate.transaction.CMTTransactionFactory" />
</properties>
</persistence-unit>
<persistence-unit name="PersistenceUnitB" transaction-type="JTA">
<class>com.javacodegeeks.snippets.enterprise.model.EmployeeB</class>
<properties>
<property name="hibernate.transaction.manager_lookup_class"
value="com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup" />
<property name="hibernate.transaction.factory_class"
value="org.hibernate.transaction.CMTTransactionFactory" />
</properties>
</persistence-unit>
</persistence>
8.2 Configure Spring container
The
applicationContext.xml
file is the configuration file of Spring.
The
<context:component-scan/>
element is used to set the package that contains all classes that the container must scan to detect the Spring beans.
The
<tx:annotation-driven/>
element is also used so that Spring is
@Transactional
-aware and can detect the
@Transactional
annotations to configure the appropriate beans with transactional behavior.
The
<jta-transaction-manager/>
element is used to detect the underlying server and choose the transaction manager available for the platform.
In
dataSourceA
and
dataSourceB
beans we define the datasources. The
com.atomikos.jdbc.AtomikosDataSourceBean
is the class set here. It uses Atomikos JTA-enabled connection pooling. It has two properties to configure. The
com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
class is set to the
xaDataSourceClass
property, whereas in the
xaProperties
we can set the properties (name,value pairs) to configure the
XADataSource
.
In
entityManagerFactoryA
and
entityManagerFactoryB
beans we set the
org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
class. It is a
FactoryBean
that creates a JPA EntityManagerFactory according to JPA’s standard container bootstrap contract. We can set the
persistence.xml
location in its
persistenceXmlLocation
property. We can set the name of the persistence unit used to create this
EntityManagerFactory
, in
persistenceUnitName
property. The datasource property is reference to the appropriate dataSource bean. The
jpaVendorAdapter
property is set to the
org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter
, that is an implementation for Hibernate EntityManager.
Finally, the
transactionManager
bean is defined, using the
org.springframework.transaction.jta.JtaTransactionManager
. It holds two properties to configure. The
transactionManager
, and the
atomikosTransactionManager
. They are references to two beans of
com.atomikos.icatch.jta.UserTransactionManager
class and
com.atomikos.icatch.jta.J2eeUserTransactionclass
respectively.
applicationContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">
<context:component-scan base-package="com.javacodegeeks.snippets.enterprise.*" />
<tx:annotation-driven />
<tx:jta-transaction-manager />
<bean id="dataSourceA" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName"><value>DataSourceA</value></property>
<property name="xaDataSourceClassName"><value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value></property>
<property name="xaProperties">
<props>
<prop key="databaseName">companyA</prop>
<prop key="serverName">localhost</prop>
<prop key="port">3306</prop>
<prop key="user">root</prop>
<prop key="password">root</prop>
<prop key="url">jdbc:mysql://localhost:3306/companyA</prop>
</props>
</property>
<property name="minPoolSize"><value>1</value></property>
</bean>
<bean id="dataSourceB" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
<property name="uniqueResourceName"><value>DataSourceB</value></property>
<property name="xaDataSourceClassName"><value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value></property>
<property name="xaProperties">
<props>
<prop key="databaseName">companyB</prop>
<prop key="serverName">localhost</prop>
<prop key="port">3306</prop>
<prop key="user">root</prop>
<prop key="password">root</prop>
<prop key="url">jdbc:mysql://localhost:3306/companyB</prop>
</props>
</property>
<property name="minPoolSize"><value>1</value></property>
</bean>
<bean id="entityManagerFactoryA" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation">
<value>classpath*:persistence.xml</value>
</property>
<property name="persistenceUnitName" value="PersistenceUnitA" />
<property name="dataSource" ref="dataSourceA" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
</bean>
</property>
</bean>
<bean id="entityManagerFactoryB" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation">
<value>classpath*:persistence.xml</value>
</property>
<property name="persistenceUnitName" value="PersistenceUnitB" />
<property name="dataSource" ref="dataSourceB" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
</bean>
</property>
</bean>
<bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
<property name="forceShutdown" value="false" />
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.J2eeUserTransaction">
<property name="transactionTimeout" value="300" />
</bean>
<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>
</beans>
8.3 Configure Web Application Deployment Descriptor
The
web.xml
file is the file that defines everything about your application that a server needs to know. Servlets and other components like filters or listeners, initialization parameters, container-managed security constraints, resources, welcome pages, etc are set here.
The servlet element declares the
AppServlet
, and the
org.springframework.web.context.support.HttpRequestHandlerServlet
class that implements it. The servlet-mapping element specifies the
/appServlet
URL pattern that invokes the servlet in a browser. In the
context-param
element we set the
contextConfigLocation
parameter, where the
applicationContext.xml
file location is defined. In listener element the
Bootstrap
listener is set to start up Spring’s
applicationContext.xml
. The
resource-ref
element is set in both datasources to define a reference lookup name to the resources. This allows the servlet code to look up the resources by a “virtual” name that is mapped to the actual location at deployment time.
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>javacodegeeks</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<display-name>AppServlet</display-name>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/appServlet</url-pattern>
</servlet-mapping>
<resource-ref>
<description>MySQL DS</description>
<res-ref-name>jdbc/DataSourceA</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
<description>MySQL DS</description>
<res-ref-name>jdbc/DataSourceB</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
</web-app>
9. Run the application in Tomcat
In order to run the application in tomcat we first have to build the project. The war produced is placed at
webapps
folder of tomcat. Then, we startup the server. After hitting on
localhost:/springexample/appServlet
in a browser, we can check on MySQL, that in both databases, companyA and companyB the tables EmployeeA and EmployeeB have one record. The message returned in the browser is the one below:
10. Rollback case
Now, let’s see what happens if one of the two transactions fail. We will change the
persistEmployee(EmployeeB employee)
method of
EmployeeBDAOImpl.java
class so as to throw an
Exception
.
EmployeeBDAO Impl.java
package com.javacodegeeks.snippets.enterprise.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Service;
import com.javacodegeeks.snippets.enterprise.model.EmployeeB;
@Service
public class EmployeeBDAOImpl implements EmployeeBDAO {
@PersistenceContext(unitName="PersistenceUnitB")
private EntityManager entityManager;
public void persistEmployee(EmployeeB employee) throws Exception {
// entityManager.persist(employee);
throw new Exception();
}
}
We build the project again and place the new war file in
webapps
file of tomcat. After starting up tomcat again, the result is the one below:
This is caused because since one of the transactions throws an exception the distributed transaction rolls back too.
This was an example of JTA multiple resource transactions in a Tomcat server, using Atomikos Transaction Manager.