使用spring+mybatis+atomikos+tomcat构建分布式事务
本文通过一个demo,介绍如何使用spring+mybatis+atomikos+tomcat构建在一个事务中涉及两个数据源的web应用。
demo功能:实现一个能成功提交和回滚的涉及两个数据库数据源的XA事务。
demo将实现:
1.一次性在两个数据库的两张表中各插入一条数据并提交。
2.一次性在两个数据库的两张表中各插入一条数据并回滚。
测试方式:restful web api
使用工具:
spring 4.1.1.RELEASE
mybatis 3.2.7
atomikos 3.7.0
tomcat 7
在mysql中建立两个schema,分别为dev和qa。并在里面分别建立一张名字表。
schema:dev
table:namaDev
id | nameDev
scheme:qa
table:nameQa
id | nameQa
对应的sql为
CREATE SCHEMA `qa` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
CREATE SCHEMA `dev` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ; CREATE TABLE `dev`.`nameDev` (
`id` BIGINT NOT NULL AUTO_INCREMENT ,
`nameDev` VARCHAR(45) NULL ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `id_UNIQUE` (`id` ASC) ); CREATE TABLE `qa`.`nameQa` (
`id` BIGINT NOT NULL AUTO_INCREMENT ,
`nameQa` VARCHAR(45) NULL ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `id_UNIQUE` (`id` ASC) );
代码分析:
本项目使用spring框架,因此首先配置相关bean
<?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:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:cache="http://www.springframework.org/schema/cache" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<context:component-scan base-package="com.xy">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<context:property-placeholder location="classpath:context/database.properties"/>
<tx:annotation-driven/> <bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
destroy-method="close" abstract="true">
<property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
<property name="poolSize" value="10" />
<property name="minPoolSize" value="10"/>
<property name="maxPoolSize" value="30"/>
<property name="borrowConnectionTimeout" value="60"/>
<property name="reapTimeout" value="20"/>
<!-- 最大空闲时间 -->
<property name="maxIdleTime" value="60"/>
<property name="maintenanceInterval" value="60"/>
<property name="loginTimeout" value="60"/>
<property name="testQuery">
<value>select 1</value>
</property>
</bean> <bean id="qadataSource" parent="abstractXADataSource">
<!-- value只要两个数据源不同就行,随便取名 -->
<property name="uniqueResourceName" value="mysql/sitestone1" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${qa.db.url}</prop>
<prop key="user">${qa.db.user}</prop>
<prop key="password">${qa.db.password}</prop>
<prop key="pinGlobalTxToPhysicalConnection">true</prop>
</props>
</property>
</bean> <bean id="devdataSource" parent="abstractXADataSource">
<!-- value只要两个数据源不同就行,随便取名 -->
<property name="uniqueResourceName" value="mysql/sitestone" />
<property name="xaDataSourceClassName"
value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
<property name="xaProperties">
<props>
<prop key="URL">${dev.db.url}</prop>
<prop key="user">${dev.db.user}</prop>
<prop key="password">${dev.db.password}</prop>
<prop key="pinGlobalTxToPhysicalConnection">true</prop>
</props>
</property>
</bean> <bean id="qasqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="qadataSource" />
<property name="mapperLocations" value="classpath*:com/xy/dao/*.xml" />
</bean> <bean id="devsqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="devdataSource" />
<property name="mapperLocations" value="classpath*:com/xy/daodev/*.xml" />
</bean> <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown">
<value>true</value>
</property>
</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 bean="atomikosTransactionManager"/>
</property>
<property name="userTransaction">
<ref bean="atomikosUserTransaction"/>
</property>
<!-- 必须设置,否则程序出现异常 JtaTransactionManager does not support custom isolation levels by default -->
<property name="allowCustomIsolationLevels" value="true"/> </bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xy.dao"/>
<property name="sqlSessionFactoryBeanName" value="qasqlSessionFactory" />
</bean> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.xy.daodev"/>
<property name="sqlSessionFactoryBeanName" value="devsqlSessionFactory" />
</bean>
</beans>
其中qadataSource和devdataSource是对应两个数据库的数据源,qasqlSessionFactory和devsqlSessionFactory是mybatis的sessionfactory,两个MapperScannerConfigurer自动将不同数据源的sql语句文件与interface自动装配起来,atomikosTransactionManager会自动管理两个atomikos的数据源的事务,即resource manager,atomikosUserTransaction为最上层的事务管理器为transaction manager。(关于RM和TM,请参见上篇博文)。
Model类如下:package com.xy.model
package com.xy.model; /**
* Created by helloworld on 2015/1/30.
*/
public class NameQa {
private long id;
private String nameQa; public long getId() {
return id;
} public void setId(long id) {
this.id = id;
} public String getNameQa() {
return nameQa;
} public void setNameQa(String nameQa) {
this.nameQa = nameQa;
}
}
nameQa class
package com.xy.model; /**
* Created by helloworld on 2015/1/30.
*/
public class NameDev {
private long id;
private String nameDev; public long getId() {
return id;
} public void setId(long id) {
this.id = id;
} public String getNameDev() {
return nameDev;
} public void setNameDev(String nameDev) {
this.nameDev = nameDev;
}
}
nameDev class
qa数据源的mybatis mapper接口 package com.xy.dao
package com.xy.dao; import com.xy.model.NameQa; /**
* Created by helloworld on 2015/1/30.
*/
public interface NameQaMapper {
int insert(NameQa nameQa);
}
NameQaMapper
dev数据源的mybatis mapper接口 package com.xy.devdao
package com.xy.daodev; import com.xy.model.NameDev; /**
* Created by helloworld on 2015/1/30.
*/
public interface NameDevMapper {
int insert(NameDev nameDev);
}
NameDevMapper
处理事务的service
package com.xy.service; import com.xy.dao.NameQaMapper;
import com.xy.daodev.NameDevMapper;
import com.xy.model.NameDev;
import com.xy.model.NameQa;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; /**
* Created by helloworld on 2015/1/30.
*/
@Service
public class NameService {
@Autowired
NameQaMapper nameQaMapper;
@Autowired
NameDevMapper nameDevMapper; @Transactional(rollbackFor = Exception.class)
public void addQaAndDev(boolean hasException) throws Exception {
NameQa nameQa = new NameQa();
nameQa.setNameQa("qa");
nameQaMapper.insert(nameQa); NameDev nameDev = new NameDev();
nameDev.setNameDev("dev");
nameDevMapper.insert(nameDev); if(hasException) {
throw new Exception();
}
} }
nameservice
controller代码
package com.xy.controller; import com.xy.service.NameService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; /**
* Created by helloworld on 2014/11/22.
*/
@Controller
public class mybatisController { @Autowired
NameService nameService; @RequestMapping(value = "/addName", method = RequestMethod.POST)
ModelMap addName(@RequestParam("hasException") boolean hasException) {
try {
nameService.addQaAndDev(hasException);
} catch (Exception e) {
e.printStackTrace();
return new ModelMap("false");
}
return new ModelMap("true");
} }
controller
将项目打成war包,命名为mybatis.war部署在tomcat上。
测试:
1.POST http://localhost:8080/mybatis/addName.json
request parameters: hasException=false 返回:true 数据添加成功
2.POST http://localhost:8080/mybatis/addName.json
request parameters: hasException=true
返回:false 两个数据库数据都未添加 源码下载:http://files.cnblogs.com/files/rain-in-sun/springmvc-mybatis-atomikos.rar
使用spring+mybatis+atomikos+tomcat构建分布式事务的更多相关文章
- 使用spring+hibernate+atomikos+tomcat构建分布式事务
本文通过一个demo,介绍如何使用spring+hibernate+atomikos+tomcat构建在一个事务中涉及两个数据源的web应用. demo功能:实现一个能成功提交和回滚的涉及两个数据库数 ...
- spring+mybatis+Atomikos JTA事务配置说明
一.概览 Atomikos是一个公司名字,旗下最著名的莫过于其Atomikos的事务管理器产品.产品分两个:一个是开源的TransactionEssentials,一个是商业的ExtremeTrans ...
- Spring Cloud Alibaba | 微服务分布式事务之Seata
Spring Cloud Alibaba | 微服务分布式事务之Seata 本篇实战所使用Spring有关版本: SpringBoot:2.1.7.RELEASE Spring Cloud:Green ...
- spring + myBatis 常见错误:注解事务不回滚
最近项目在用springMVC+spring+myBatis框架,在配置事务的时候发现一个事务不能回滚的问题. 刚开始配置如下:springMVC.xml配置内容: spring.xml配置内容 从上 ...
- 事务隔离级别与传播机制,spring+mybatis+atomikos实现分布式事务管理
1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). 原子性(Atomicity):即事务是不可分割的最小工作单 ...
- Spring事务隔离级别与传播机制详解,spring+mybatis+atomikos实现分布式事务管理
原创说明:本文为本人原创作品,绝非他处转载,转账请注明出处 1.事务的定义:事务是指多个操作单元组成的合集,多个单元操作是整体不可分割的,要么都操作不成功,要么都成功.其必须遵循四个原则(ACID). ...
- spring+mybatis+atomikos 实现JTA事务
1. 选择哪种transaction manager? 在单数据源情况下,JDBC,Hibernate,ibatis等自带的 transaction manager已能用于处理事务. ...
- 3分钟搞定SpringBoot+Mybatis+druid多数据源和分布式事务
文章来自: https://blog.csdn.net/qq_29242877/article/details/79033287 在一些复杂的应用开发中,一个应用可能会涉及到连接多个数据源,所谓多数据 ...
- SpringMVC+MyBatis+JMS+JTA(分布式事务)
SpringMVC+MyBatis 相信已经是如今企业开发中经常使用技术了. 由于一些需求,我们须要集成JMS(我使用的是ActiveMQ).大家应该都知道.MQ也能够觉得是一个数据源.数据也是数据源 ...
随机推荐
- cookie 编码问题
问题描述: Control character in cookie value or attribute. 解决方案: 1.前台编码 encodeURIComponent(str) 2.后台解码 原 ...
- 行内onclick使用遇坑--------作用域与传入字符串
问题一:行内onclick触发的函数放在$(funtion(){})内报错,错误代码如下: <input type="button" value="确定" ...
- 如何克隆路由器MAC地址,怎么操作?
路由器的“MAC地址克隆”的意思是: 不克隆时,从外网访问你的电脑,获得的MAC地址是路由器的mac地址. 克隆后,从外网访问你的电脑,获得的MAC地址是你电脑网卡的mac地址. 实用举例如下: 中国 ...
- 【android-cocos2d-X 环境配置】在Mac下搭建Cocos2d-X-android开发环境!
转自:http://blog.csdn.net/dingkun520wy/article/details/17097593 (1)下载 首先要下载好要用到的东西: 1.android-SDK 地址是 ...
- PostgreSQL的 initdb 源代码分析之十二
继续分析 /* Now create all the text config files */ setup_config(); 将其展开: 实质就是,确定各种参数,分别写入 postgresql.co ...
- 【M21】利用重载技术避免隐式类型转换
1.考虑UPint 的加法+,UPint a, b, result; 为了使result = a+10; result= 10+a; 都能通过编译,操作符重载如下: const UPint opera ...
- cdoj 1255 斓少摘苹果 贪心
斓少摘苹果 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1255 Descr ...
- Codeforces Round #313 (Div. 2) B. Gerald is into Art 水题
B. Gerald is into Art Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/560 ...
- SQL SERVER NVARCHAR字段INSERT 中文乱码问题解决
INSERT INTO IPatient ( UID, PatientNo, PatientName, PatientGender, Birthday, BloodType, Country, Nat ...
- 安卓Activity界面切换添加动画特效
在Android 2.0之后有了overridePendingTransition() ,其中里面两个参数,一个是前一个activity的退出两一个activity的进入, @Override pub ...