文档章节

分布式事务JTA实现Atomikos与Spring集成实践

secondriver
 secondriver
发布于 2015/09/17 09:23
字数 1218
阅读 134
收藏 0

  理解分布式事务JTA原理参见:http://www.ibm.com/developerworks/cn/java/j-lo-jta/

  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依赖图:

 wKiom1Vu-WuiaLnzAACxcXC9yhs625.jpg

 

 Postgresql数据库驱动:

<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<version>9.2-1004-jdbc4</version>
		</dependency>

 注:文中使用的是Postgresql V9.2

 

 javax.transaction.transaction-api.1.1:

 

<!-- Include in javaee-api -->
		<!-- 
		<dependency>
			<groupId>javax.transaction</groupId>
			<artifactId>transaction-api</artifactId>
			<version>1.1</version>
		</dependency>
		 -->

 

 

<!-- JavaEE -->
		<!-- javaee-api包含了JavaEE规范中的api,如servlet-api,persistence-api, transaction-api等 -->
		<dependency>
			<groupId>javax</groupId>
			<artifactId>javaee-api</artifactId>
			<version>7.0</version>
		</dependency>

 注:根据需要选择其一即可。


 Spring,Junit依赖这里省略。


 1.2 创建数据库以及表

   数据库分别是:javaee,tomdb

   wKioL1Vu-8eAXWY-AADUZDXsd7M684.jpg


 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,要开启XA需要设置该值至少和max_connections参数值一样大,该参数在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"  init-method="init" destroy-method="close">
		<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();
			try {
				utm.rollback();
			} catch (IllegalStateException | SecurityException
					| SystemException e1) {
				e1.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");
		Transaction tx =null;
		try {
		 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();
			if(tx!=null){
			    try {
					tx.rollback();
				} catch (IllegalStateException | SystemException e1) {
					e1.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();
			try {
				utx.rollback();
			} catch (IllegalStateException | SecurityException
					| SystemException e1) {
				e1.printStackTrace();
			}
		}
	}


 使用上述三种UserTransaction进行测试,其中test1方法是成功执行,test2方法是执行失败的(因为插入的值长度超过的字段长度限制)。通过分析之后,如果分布式事物控制正确,那么数据库中写入的值对于两张不同的表而言,是没有数字值被写入的。如图所示:

 wKiom1Vu_tiwRFwEAAHJhvqOEPQ597.jpg


 在测试过程中,经过对比确实达到了分布式事务控制的效果。

 整个操作的架构图如下(摘自Atomikos Blog)

 wKiom1VvoGrCpUisAAFjdTzZnG0617.jpg


 关于JTA原理文章开始提到的那篇文章,写的很详细和清晰,可以细细阅读和理解。

本文出自 “野马红尘” 博客,请务必保留此出处http://aiilive.blog.51cto.com/1925756/1658102

© 著作权归作者所有

secondriver
粉丝 10
博文 229
码字总数 233821
作品 0
广州
程序员
私信 提问
分布式事务系列(开篇)提出疑问和研究过程

1 前言 系列目录 - 分布式事务系列(开篇)提出疑问和研究过程- 分布式事务系列(1.1)Spring事务管理器PlatformTransactionManager源码分析- 分布式事务系列(1.2)Spring事务体系- 分布式事...

乒乓狂魔
2015/05/12
6.6K
7
分布式事务系列(4.1)Atomikos的分布式案例

1 系列目录 - 分布式事务系列(开篇)提出疑问和研究过程- 分布式事务系列(1.1)Spring事务管理器PlatformTransactionManager源码分析- 分布式事务系列(1.2)Spring事务体系- 分布式事务系...

乒乓狂魔
2015/06/01
5.7K
4
【分布式事务系列】提出疑问和研究过程

分布式事务 【分布式事务系列】提出疑问和研究过程 对于我们这种初学者,可能会使用Spring带给我们的@Transactional,可能了解JTA,可能会使用jotm、atomikos,又会遇到一些名词XA,支持XA的...

陶邦仁
2015/12/09
568
0
分布式事务开源解决方案用例版--hihsoft-atomikos

【组件价值】 Atomikos 是一款 Java/JTA 事务处理工具 与spring完美结合,实现配置化分布式事务 多数据源分布式事务的开源解决方案 跨平台,不受应用服务器限制 也是学习spring、mybatis、j...

平凡哥
2014/08/07
1K
1
spring+mybatis+atomikos 实现JTA事务

atomikos支持一个分布式事务,结合spring,可以很好的满足一个应用访问多个库的需要。 atomikos 结合spring做配置也很简单 1.配置datasource <!-- 第一个数据库 --><bean id="dataSource" c...

lavafree
2013/01/04
7.3K
5

没有更多内容

加载失败,请刷新页面

加载更多

golang-字符串-地址分析

demo package mainimport "fmt"func main() {str := "map.baidu.com"fmt.Println(&str, str)str = str[0:5]fmt.Println(&str, str)str = "abc"fmt.Println(&s......

李琼涛
今天
4
0
Spring Boot WebFlux 增删改查完整实战 demo

03:WebFlux Web CRUD 实践 前言 上一篇基于功能性端点去创建一个简单服务,实现了 Hello 。这一篇用 Spring Boot WebFlux 的注解控制层技术创建一个 CRUD WebFlux 应用,让开发更方便。这里...

泥瓦匠BYSocket
今天
8
0
从0开始学FreeRTOS-(列表与列表项)-3

FreeRTOS列表&列表项的源码解读 第一次看列表与列表项的时候,感觉很像是链表,虽然我自己的链表也不太会,但是就是感觉很像。 在FreeRTOS中,列表与列表项使用得非常多,是FreeRTOS的一个数...

杰杰1号
今天
8
0
Java反射

Java 反射 反射是框架设计的灵魂(使用的前提条件:必须先得到代表的字节码的 Class,Class 类 用于表示.class 文件(字节码)) 一、反射的概述 定义:JAVA 反射机制是在运行状态中,对于任...

zzz1122334
今天
6
0
聊聊nacos的LocalConfigInfoProcessor

序 本文主要研究一下nacos的LocalConfigInfoProcessor LocalConfigInfoProcessor nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/config/impl/LocalConfigInfoProcessor.java p......

go4it
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部