赞
踩
JTA实现产品介绍: http://blog.chinaunix.net/uid-122937-id-3793220.html
Atomikos官网无法访问,不过Maven中央库中具atomikos包。Atomikos集成Spring,Hibernate,Mybatis网上文章比较多,本文是通过JavaSE的方式借用Spring配置来测试Atomikos对JTA的实现。
下面做一件事,就是两(+)个数据库,在一个事务里对其分别对数据库操作验证操作的原子性,即要么两个数据库的操作都成功,要么都失败。
1.准备工作
1.1 Maven pom.xml中添加依赖包
atomikos:(目前最新版)
<dependency>
<groupId>com.atomikos</groupId>
<artifactId>transactions-jdbc</artifactId>
<version>3.9.3</version>
</dependency>
jar依赖图:
Postgresql数据库驱动:
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.2-1004-jdbc4</version>
</dependency>
Spring,Junit依赖这里省略。
1.2 创建数据库以及表
数据库分别是:javaee,tomdb
2.在项目中添加配置文件
spring-jta.xml 和transaction.properties文件,spring-jta.xml在src/main/resources/integration下,transaction.properties在src/main/resources/下。
2.1在spring-jta.xml中配置两个XADataSource:
<!-- 使用分布式事务时设置Postgresql的max_prepared_transactions为大于0的值,该值默认是0 -->
<!-- 数据库A -->
<bean id="a" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="pg/a" />
<property name="xaDataSourceClassName" value="org.postgresql.xa.PGXADataSource" />
<property name="xaProperties">
<props>
<prop key="user">postgres</prop>
<prop key="password">postgres</prop>
<prop key="serverName">localhost</prop>
<prop key="portNumber">5432</prop>
<prop key="databaseName">tomdb</prop>
</props>
</property>
<property name="poolSize" value="10" />
<property name="reapTimeout" value="20000" />
</bean>
<bean id="b" class="com.atomikos.jdbc.AtomikosDataSourceBean"
init-method="init" destroy-method="close">
<property name="uniqueResourceName" value="pg/b" />
<property name="xaDataSourceClassName" value="org.postgresql.xa.PGXADataSource" />
<property name="xaProperties">
<props>
<prop key="user">postgres</prop>
<prop key="password">postgres</prop>
<prop key="serverName">localhost</prop>
<prop key="portNumber">5432</prop>
<prop key="databaseName">javaee</prop>
</props>
</property>
<property name="poolSize" value="10" />
<property name="reapTimeout" value="20000" />
</bean>
说明:
Postgresql的max_prepared_transactions参数值默认是0,要开启分布式事务需要设置为大于0的值,该参数在PostgreSQL\9.3\data\postgresql.conf文件中。
PGXADataSource的父类BaseDataSource没有url属性,可需要分别设置serverName,portNumber,databaseName等属性。不同的数据库驱动有不同的实现方法。
2.2 配置事务管理对象和UserTransaction接口实现
<!-- atomikos事务管理 -->
<bean id="atomikosUserTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager">
<description>UserTransactionManager</description>
<property name="forceShutdown" value="true" />
</bean>
<bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
<property name="transactionTimeout" value="300" />
</bean>
<bean id="transactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="atomikosUserTransactionManager"></property>
</bean>
上面三个Bean可以独立使用来进行事务控制,具体看下面3。
3. 编写测试
3.1 使用atomikosUserTransactionManager对象测试(TestAtomikos1.java)
- package secondriver.springsubway.example.jta;
-
- import java.sql.Connection;
- import java.sql.SQLException;
-
- import javax.transaction.HeuristicMixedException;
- import javax.transaction.HeuristicRollbackException;
- import javax.transaction.NotSupportedException;
- import javax.transaction.RollbackException;
- import javax.transaction.SystemException;
-
- import org.junit.BeforeClass;
- import org.junit.Test;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
-
- import com.atomikos.icatch.jta.UserTransactionManager;
- import com.atomikos.jdbc.AtomikosDataSourceBean;
-
- public class TestAtomikos1 {
-
- public static ApplicationContext ctx;
-
- @BeforeClass
- public static void beforeClass() {
- ctx = new ClassPathXmlApplicationContext(
- "classpath:integration/spring-jta.xml");
- }
-
- public static void afterClass() {
- ctx = null;
- }
-
- @Test
- public void test1() {
- exe("abc", "abc");
- }
-
- @Test
- public void test2() {
- exe("123=", "123");
- }
-
- public void exe(String av, String bv) {
-
- AtomikosDataSourceBean adsA = (AtomikosDataSourceBean) ctx.getBean("a");
- AtomikosDataSourceBean adsB = (AtomikosDataSourceBean) ctx.getBean("b");
- Connection connA;
- Connection connB;
- UserTransactionManager utm = (UserTransactionManager) ctx
- .getBean("atomikosUserTransactionManager");
- try {
- utm.begin();
- connA = adsA.getConnection();
- connB = adsB.getConnection();
- connA.prepareStatement(
- "insert into jta_temp (value) values('" + av + "')")
- .execute();
- connB.prepareStatement(
- "insert into jta_temp (value) values('" + bv + "')")
- .execute();
- utm.commit();
- } catch (SQLException | NotSupportedException | SystemException
- | SecurityException | IllegalStateException | RollbackException
- | HeuristicMixedException | HeuristicRollbackException e) {
- e.printStackTrace();
- }
- }
- }
3.2使用Spring的JtaUserTransactionManager对象测试(TestAtomikos2.java 修改TestAtomikos1.java中的exe方法即可)
- @Test
- public void test1() {
- exe("abc", "abc");
- }
-
- @Test
- public void test2() {
- exe("123=", "123");
- }
public void exe(String av, String bv) {
TransactionFactory txm = (TransactionFactory) ctx
.getBean("transactionManager");
JdbcTemplate a = (JdbcTemplate) ctx.getBean("jdbcTemplateA");
JdbcTemplate b = (JdbcTemplate) ctx.getBean("jdbcTemplateB");
try {
Transaction tx = txm.createTransaction("tx-name-define", 10000);
a.update("insert into jta_temp (value) values('" + av + "')");
b.update("insert into jta_temp (value) values('" + bv + "')");
tx.commit();
} catch (NotSupportedException | SystemException | SecurityException
| RollbackException | HeuristicMixedException
| HeuristicRollbackException e) {
e.printStackTrace();
}
}
3.3使用atomikosUserTransaction Bean对象进行测试(TestAtomikos3.java 修改TestAtomikos1.java中的exe方法即可)
- @Test
- public void test1() {
- exe("abc", "abc");
- }
-
- @Test
- public void test2() {
- exe("123", "123=");
- }
public void exe(String av, String bv) {
AtomikosDataSourceBean adsA = (AtomikosDataSourceBean) ctx.getBean("a");
AtomikosDataSourceBean adsB = (AtomikosDataSourceBean) ctx.getBean("b");
Connection connA;
Connection connB;
UserTransaction utx = (UserTransaction) ctx
.getBean("atomikosUserTransaction");
try {
utx.begin();
connA = adsA.getConnection();
connB = adsB.getConnection();
connA.prepareStatement(
"insert into jta_temp (value) values('" + av + "')")
.execute();
connB.prepareStatement(
"insert into jta_temp (value) values('" + bv + "')")
.execute();
utx.commit();
} catch (SQLException | NotSupportedException | SystemException
| SecurityException | IllegalStateException | RollbackException
| HeuristicMixedException | HeuristicRollbackException e) {
e.printStackTrace();
}
}
使用上述三种UserTransaction进行测试,其中test1方法是成功执行,test2方法是执行失败的(因为插入的值长度超过的字段长度限制)。通过分析之后,如果分布式事物控制正确,那么数据库中写入的值对于两张不同的表而言,是没有数字值被写入的。如图所示:
在测试过程中,经过对比确实达到了分布式事务控制的效果。
关于JTA原理文章开始提到的那篇文章,写的很详细和清晰,可以细细阅读和理解。
- <?xml version="1.0" encoding="UTF-8"?>
- <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:tx="http://www.springframework.org/schema/tx"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:jdbc="http://www.springframework.org/schema/jdbc"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
- http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
- http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
- <aop:aspectj-autoproxy />
-
-
-
- <!-- 采用注释的方式配置bean -->
- <context:annotation-config />
- <bean id="springContextHolder"
- class="com.hihsoft.framework.core.utils.SpringContextHolder"
- lazy-init="false" />
- <bean id="propertyConfigurerForProject_framework"
- class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="order" value="1" />
- <property name="ignoreUnresolvablePlaceholders" value="true" />
- <property name="location">
- <value>classpath:jdbc.properties</value>
- </property>
- </bean>
- <bean id="db1_dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
- init-method="init" destroy-method="close">
- <property name="uniqueResourceName" value="db1_dataSource" />
- <property name="xaDataSourceClassName"
- value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
-
- <property name="xaProperties">
- <props>
- <prop key="user">${jdbc.username}</prop>
- <prop key="password">${jdbc.password}</prop>
- <prop key="URL">${jdbc.url}</prop>
- </props>
- </property>
- <!-- 连接池里面连接的个数? -->
- <property name="poolSize" value="3" />
- </bean>
-
- <bean id="db2_dataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean"
- init-method="init" destroy-method="close">
- <property name="uniqueResourceName" value="db2_dataSource" />
- <property name="xaDataSourceClassName"
- value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
- <property name="xaProperties">
- <props>
- <prop key="user">${jdbc.username.hihsoft}</prop>
- <prop key="password">${jdbc.password.hihsoft}</prop>
- <prop key="URL">${jdbc.url.hihsoft}</prop>
- </props>
- </property>
- <!-- 连接池里面连接的个数? -->
- <property name="poolSize" value="3" />
- </bean>
- <!-- enable transaction demarcation with annotations -->
- <tx:annotation-driven transaction-manager="jtaTransactionManager"
- proxy-target-class="false" />
-
- <!-- atomikos事务管理器 -->
- <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="300" />
- </bean>
-
- <!-- spring 事务管理器 -->
- <bean id="jtaTransactionManager"
- class="org.springframework.transaction.jta.JtaTransactionManager">
- <property name="transactionManager" ref="atomikosTransactionManager" />
- <property name="userTransaction" ref="atomikosUserTransaction" />
- <property name="allowCustomIsolationLevels" value="true" />
- </bean>
- <bean id="db1_sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
- <property name="dataSource" ref="db1_dataSource" />
- <property name="mapperLocations"
- value="classpath*:com/hihsoft/db1/persistence/**/*.xml" />
- </bean>
-
- <bean id="db1MapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
- <property name="basePackage" value="com.hihsoft.db1.persistence" />
- <property name="sqlSessionFactoryBeanName" value="db1_sqlSessionFactory" />
- </bean>
- <bean id="db2_sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
- <property name="dataSource" ref="db2_dataSource" />
- <property name="mapperLocations"
- value="classpath*:com/hihsoft/db2/persistence/**/*.xml" />
- </bean>
-
- <bean id="db2MapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
- <property name="basePackage" value="com.hihsoft.db2.persistence" />
- <property name="sqlSessionFactoryBeanName" value="db2_sqlSessionFactory" />
- </bean>
- <!-- mybatis日志打印 -->
- <bean class="org.apache.ibatis.logging.LogFactory" init-method="useStdOutLogging"></bean>
- <!-- spring jdbc ibatis mybatis初始化数据导入 -->
- <jdbc:initialize-database data-source="db1_dataSource"
- enabled="false" ignore-failures="ALL">
- <jdbc:script location="classpath:/resources/dbcfg/initframework_db1.sql"
- encoding="UTF-8" />
- </jdbc:initialize-database>
- <jdbc:initialize-database data-source="db2_dataSource"
- enabled="false" ignore-failures="ALL">
- <jdbc:script location="classpath:/resources/dbcfg/initframework_db2.sql"
- encoding="UTF-8" />
- </jdbc:initialize-database>
- <!-- 扫描范围 -->
- <context:component-scan base-package="com.hihsoft">
- <context:exclude-filter type="annotation"
- expression="org.springframework.stereotype.Controller" />
- </context:component-scan>
-
-
-
- <!-- 获取bean工具注入 -->
- </beans>
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。