带有Atomikos示例的Tomcat中的Spring JTA多个资源事务
在本教程中,我们将向您展示如何使用Atomikos Transaction Manager在Tomcat服务器中实现JTA多个资源事务。 Atomicos事务管理器为分布式事务提供支持。 这些是多阶段事务,通常使用多个数据库,必须以协调的方式提交。 分布式事务由XA standard
描述。 XA
事务管理器(例如Atomikos)如何告知数据库什么事务作为正在进行的事务的一部分,以及如何在每次事务结束时执行两阶段提交(2PC)协议。
在这里,我们将创建映射到两个不同数据库的简单实体类,并尝试使用一个分布式事务将这些类的对象持久保存到数据库中。 我们还将看到当基础事务之一回滚时会发生什么。
我们首选的开发环境是Eclipse 。 我们正在使用Eclipse Juno(4.2)版本以及Maven Integration插件版本3.1.0。 您可以从Eclipse的这里从和Maven Eclipse插件这里 。 用于Eclipse的Maven插件的安装不在本教程的讨论范围内,因此将不予讨论。 我们还使用Spring 3.2.3和JDK 7_u_21。
Tomcat 7是使用的应用程序服务器。 Hibernate版本为4.1.9,示例中使用的数据库为MySQL Database Server 5.6。
让我们开始,
1.创建一个新的Maven项目
转到文件->项目-> Maven-> Maven项目。
在向导的“选择项目名称和位置”页面中,确保未选中 “创建简单项目(跳过原型选择)”选项,单击“下一步”以继续使用默认值。
在这里,必须添加用于创建Web应用程序的Maven原型。 单击“添加原型”并添加原型。 将“ Archetype组ID”变量设置为"org.apache.maven.archetypes"
,将“ Archetype构件ID”变量设置为"maven-archetype-webapp"
,并将“ Archetype版本”设置为"1.0"
。 点击“确定”继续。
在向导的“输入工件ID”页面中,您可以定义项目的名称和主程序包。 将“ Group Id”变量设置为"com.javacodegeeks.snippets.enterprise"
,将“ Artifact Id”变量设置为"springexample"
。 前面提到的选择将主项目包组成为"com.javacodegeeks.snippets.enterprise.springexample"
,项目名称为"springexample"
。 将“ Package”变量设置为"war"
,以便创建一个war文件以部署到tomcat服务器。 点击“完成”退出向导并创建您的项目。
Maven项目结构如下所示:
-
它包含以下文件夹:
- / src / main / java文件夹,其中包含应用程序动态内容的源文件,
- / src / test / java文件夹包含用于单元测试的所有源文件,
- / src / main / resources文件夹包含配置文件,
- / target文件夹包含已编译和打包的可交付成果,
- / src / main / resources / webapp / WEB-INF文件夹包含Web应用程序的部署描述符,
- pom.xml是项目对象模型(POM)文件。 包含所有项目相关配置的单个文件。
2.添加Spring 3.2.3依赖项
- 在POM编辑器的“概述”页面上找到“属性”部分,并进行以下更改:
创建一个新属性,名称为org.springframework.version ,值3.2.3RELEASE 。 - 导航到POM编辑器的“依赖关系”页面,并创建以下依赖关系(您应在该页面的“依赖关系详细信息”部分中填写“ GroupId”,“工件ID”和“版本”字段):
组ID: org.springframework工件ID: spring-web版本: $ {org.springframework.version}
另外,您可以在Maven的pom.xml
文件中添加Spring依赖项,方法是直接在POM编辑器的“ Pom.xml”页面上对其进行编辑,如下所示:
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>
如您所见,Maven以声明方式管理库依赖关系。 创建本地存储库(默认情况下,位于{user_home} /。m2文件夹下),所有必需的库都从公共存储库下载并放置在该库中。 此外,库内的依赖关系会自动解决和处理。
3.添加所有必需的依赖项
此处设置了设置atomosos事务管理器所需的所有依赖项。
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.创建实体类
EmployeeA.java
和EmployeeB.java
是Entity类。 他们使用javax.persistence
批注映射到不同数据库中的表EMPLOYEEA
和EMPLOYEEB
。 特别地, @Entity
注释指定每个类是一个实体。 @Table
注释指定带注释的实体的主表。 @Column
批注用于为持久字段指定一个映射列,而@Id
批注指定每个实体的主键字段。
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.创建DAO类
实现的数据访问对象是EmployeeADAOImpl.java
和EmployeeBDAOImpl.java
类。 它们使用@Service
注释进行注释,表明它们是Spring Bean,因此允许Spring自动检测它们。 它们都使用javax.persistence.EntityManager
与数据库进行交互。
EntityManager
实例与持久性上下文关联。 持久性上下文是一组实体实例,其中对于任何持久性实体标识,都有一个唯一的实体实例。 在持久性上下文中,管理实体实例及其生命周期。 EntityManager
API用于创建和删除持久实体实例,通过其主键查找实体以及查询实体。 在persistence.xml
文件中配置了EntityManager
,对此进行了描述
在8.1节中。
可以由给定EntityManager实例管理的实体集由持久性单元定义。 持久性单元定义了与应用程序相关或分组的所有类的集合,并且所有类在映射到单个数据库时必须共置。
EntityManager
通过@PersistenceContext
注释注入到每个DAO中,在该注释中设置了每个持久性单元的名称,如persistence.xml
文件中所定义。
在两个DAO中都实现了一种基本的persist方法,使用EntityManager
的persist(Object entity)
API方法为数据库创建一个对象。
DAO及其接口如下所示:
雇员ADAO.java
package com.javacodegeeks.snippets.enterprise.dao; import com.javacodegeeks.snippets.enterprise.model.EmployeeA; public interface EmployeeADAO { void persistEmployee(EmployeeA employee); }
雇员ADAO 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); } }
雇员BDAO .java
package com.javacodegeeks.snippets.enterprise.dao; import com.javacodegeeks.snippets.enterprise.model.EmployeeB; public interface EmployeeBDAO { void persistEmployee(EmployeeB employee) throws Exception; }
雇员BDAO 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.创建服务类
EmployeeADAOImpl.java
和EmployeeBDAOImpl.java
类被注入EmployeeServiceImpl.java
类。 因此,在此处实现的persistEmployees(EmployeeA employeeA, EmployeeB employeeB)
方法中,将调用DAO的方法来执行与数据库的基本交互。 EmployeeServiceImpl.java
类也带有@Service
注释,表明它是一个Spring Bean,因此允许Spring自动检测到它。
@Transactional
批注放置在方法之前,以表示在调用该方法时创建了一个事务。 该事务是全局容器管理的事务,将在Spring配置文件中进行配置。
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.创建一个servlet以运行该应用程序
AppServlet.java
类是一个简单的servlet,它实现org.springframework.web.HttpRequestHandler
并覆盖其handleRequest(HttpServletRequest req, HttpServletResponse resp)
API方法。 EmployeeService
通过@Autowire
注释注入到此处。 在handleRequest(HttpServletRequest req, HttpServletResponse resp)
API方法中使用它来持久存储新的EmployeeA
和新的EmployeeB
对象。 如果该方法成功返回,则该方法还返回成功消息,如果该方法引发异常,则返回回滚消息。
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(35); EmployeeB em2 = new EmployeeB(); em2.setId("123"); em2.setName("Mary"); em2.setAge(31); 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.配置应用程序
8.1配置持久性单元
如上所述,在persistence.xml
文件中配置了entityManager
和与每个数据库关联的持久性单元。 在这里,我们定义了两个持久性单元。 在每个persistence-unit
元素中,我们定义与持久性单元关联的实体类。 hibernate.transaction.manager_lookup_class
属性设置为com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
。 hibernate.transaction.factory_class
属性设置为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配置Spring容器
applicationContext.xml
文件是Spring的配置文件。
<context:component-scan/>
元素用于设置包含容器必须扫描以检测Spring Bean的所有类的包。
还使用<tx:annotation-driven/>
元素,以便Spring具有@Transactional
感知,并可以检测@Transactional
注释以配置具有事务行为的适当bean。 <jta-transaction-manager/>
元素用于检测基础服务器并选择可用于平台的事务管理器。
在dataSourceA
和dataSourceB
bean中,我们定义了数据源。 com.atomikos.jdbc.AtomikosDataSourceBean
是此处设置的类。 它使用支持Atomikos JTA的连接池。 它具有两个要配置的属性。 com.mysql.jdbc.jdbc2.optional.MysqlXADataSource
类设置为xaDataSourceClass
属性,而在xaProperties
我们可以设置属性(名称,值对)以配置XADataSource
。
在entityManagerFactoryA
和entityManagerFactoryB
bean中,我们设置了org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
类。 它是一个FactoryBean
,可根据JPA的标准容器引导合同创建JPA EntityManagerFactory
。 我们可以在其persistenceXmlLocation
属性中设置persistence.xml
位置。 我们可以在persistenceUnitName
属性中设置用于创建此EntityManagerFactory
的持久性单元的名称。 datasource
属性是对适当的dataSource
bean的引用。 jpaVendorAdapter
属性设置为org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter
,它是Hibernate EntityManager
的实现。
最后,使用org.springframework.transaction.jta.JtaTransactionManager
定义transactionManager
bean。 它具有两个要配置的属性。 transactionManager
和atomikosTransactionManager
。 它们分别引用了com.atomikos.icatch.jta.UserTransactionManager
类和com.atomikos.icatch.jta.J2eeUserTransaction
类的两个bean。
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配置Web应用程序部署描述符
web.xml
文件是定义服务器需要了解的有关应用程序的所有内容的文件。 此处设置了Servlet和其他组件,如过滤器或侦听器,初始化参数,容器管理的安全性约束,资源,欢迎页面等。
servlet
元素声明AppServlet
,并声明实现它的org.springframework.web.context.support.HttpRequestHandlerServlet
类。 servlet-mapping
元素指定在浏览器中调用servlet的/appServlet
URL模式。 在context-param
元素中,我们设置了contextConfigLocation
参数,其中定义了applicationContext.xml
文件位置。 在listener
元素中,将Bootstrap侦听器设置为启动Spring的applicationContext.xml
。 在两个数据源中都设置了resource-ref
元素,以定义对资源的引用查找名称。 这允许servlet代码通过在部署时映射到实际位置的“虚拟”名称来查找资源。
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.在Tomcat中运行应用程序
为了在tomcat中运行应用程序,我们首先必须构建项目。 产生的war
被放置在tomcat的webapps文件夹中。 然后,我们启动服务器。 撞上之后
localhost:8080/springexample/appServlet
在浏览器中,我们可以检查在MySQL,这两个数据库, companyA
和companyB
表EmployeeA
和EmployeeB
有一个记录。 浏览器中返回的消息是以下消息:
10.回滚情况
现在,让我们看看如果两个事务之一失败了会发生什么。 我们将更改EmployeeBDAOImpl.java
类的persistEmployee(EmployeeB employee)
方法,以引发Exception
。
雇员BDAO 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(); } }
我们再次构建该项目,并将新的war
文件放入tomcat的webapps文件中。 再次启动tomcat之后,结果如下:
这是由于事务之一引发异常而导致分布式事务也会回滚。
这是使用Atomikos事务管理器在Tomcat服务器中进行JTA多个资源事务的示例。
下载本教程的Eclipse项目: SpringJTAatomicosTomcatExample.zip