本文通过一个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为
1 CREATE SCHEMA `qa` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
2 CREATE SCHEMA `dev` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci ;
3
4 CREATE TABLE `dev`.`nameDev` (
5 `id` BIGINT NOT NULL AUTO_INCREMENT ,
6 `nameDev` VARCHAR(45) NULL ,
7 PRIMARY KEY (`id`) ,
8 UNIQUE INDEX `id_UNIQUE` (`id` ASC) );
9
10 CREATE TABLE `qa`.`nameQa` (
11 `id` BIGINT NOT NULL AUTO_INCREMENT ,
12 `nameQa` VARCHAR(45) NULL ,
13 PRIMARY KEY (`id`) ,
14 UNIQUE INDEX `id_UNIQUE` (`id` ASC) );
代码分析:
本项目使用spring框架,因此首先配置相关bean
1
2
9
10
11
12
13
14
15
17
18
19
20
21
22
23
24
25
26
27
28 select 1
29
30
31
32
33
34
35
37
38
39 ${qa.db.url}
40 ${qa.db.user}
41 ${qa.db.password}
42 true
43
44
45
46
47
48
49
50
52
53
54 ${dev.db.url}
55 ${dev.db.user}
56 ${dev.db.password}
57 true
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
76
77 true
78
79
80
81
82
83
84
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
其中qadataSource和devdataSource是对应两个数据库的数据源,qasqlSessionFactory和devsqlSessionFactory是mybatis的sessionfactory,两个MapperScannerConfigurer自动将不同数据源的sql语句文件与interface自动装配起来,atomikosTransactionManager会自动管理两个atomikos的数据源的事务,即resource manager,atomikosUserTransaction为最上层的事务管理器为transaction manager。(关于RM和TM,请参见上篇博文)。
Model类如下:package com.xy.model
1 package com.xy.model;
2
3 /**
4 * Created by helloworld on 2015/1/30.
5 */
6 public class NameQa {
7 private long id;
8 private String nameQa;
9
10 public long getId() {
11 return id;
12 }
13
14 public void setId(long id) {
15 this.id = id;
16 }
17
18 public String getNameQa() {
19 return nameQa;
20 }
21
22 public void setNameQa(String nameQa) {
23 this.nameQa = nameQa;
24 }
25 }
nameQa class
1 package com.xy.model;
2
3 /**
4 * Created by helloworld on 2015/1/30.
5 */
6 public class NameDev {
7 private long id;
8 private String nameDev;
9
10 public long getId() {
11 return id;
12 }
13
14 public void setId(long id) {
15 this.id = id;
16 }
17
18 public String getNameDev() {
19 return nameDev;
20 }
21
22 public void setNameDev(String nameDev) {
23 this.nameDev = nameDev;
24 }
25 }
nameDev class qa数据源的mybatis mapper接口 package com.xy.dao
1 package com.xy.dao;
2
3 import com.xy.model.NameQa;
4
5 /**
6 * Created by helloworld on 2015/1/30.
7 */
8 public interface NameQaMapper {
9 int insert(NameQa nameQa);
10 }
NameQaMapper dev数据源的mybatis mapper接口 package com.xy.devdao
1 package com.xy.daodev;
2
3 import com.xy.model.NameDev;
4
5 /**
6 * Created by helloworld on 2015/1/30.
7 */
8 public interface NameDevMapper {
9 int insert(NameDev nameDev);
10 }
NameDevMapper 处理事务的service
1 package com.xy.service;
2
3 import com.xy.dao.NameQaMapper;
4 import com.xy.daodev.NameDevMapper;
5 import com.xy.model.NameDev;
6 import com.xy.model.NameQa;
7 import org.springframework.beans.factory.annotation.Autowired;
8 import org.springframework.stereotype.Service;
9 import org.springframework.transaction.annotation.Transactional;
10
11 /**
12 * Created by helloworld on 2015/1/30.
13 */
14 @Service
15 public class NameService {
16 @Autowired
17 NameQaMapper nameQaMapper;
18 @Autowired
19 NameDevMapper nameDevMapper;
20
21 @Transactional(rollbackFor = Exception.class)
22 public void addQaAndDev(boolean hasException) throws Exception {
23 NameQa nameQa = new NameQa();
24 nameQa.setNameQa("qa");
25 nameQaMapper.insert(nameQa);
26
27 NameDev nameDev = new NameDev();
28 nameDev.setNameDev("dev");
29 nameDevMapper.insert(nameDev);
30
31 if(hasException) {
32 throw new Exception();
33 }
34 }
35
36
37 }
nameservice controller代码
1 package com.xy.controller;
2
3 import com.xy.service.NameService;
4 import org.springframework.beans.factory.annotation.Autowired;
5 import org.springframework.stereotype.Controller;
6 import org.springframework.ui.ModelMap;
7 import org.springframework.web.bind.annotation.RequestMapping;
8 import org.springframework.web.bind.annotation.RequestMethod;
9 import org.springframework.web.bind.annotation.RequestParam;
10
11 /**
12 * Created by helloworld on 2014/11/22.
13 */
14 @Controller
15 public class mybatisController {
16
17 @Autowired
18 NameService nameService;
19
20 @RequestMapping(value = "/addName", method = RequestMethod.POST)
21 ModelMap addName(@RequestParam("hasException") boolean hasException) {
22 try {
23 nameService.addQaAndDev(hasException);
24 } catch (Exception e) {
25 e.printStackTrace();
26 return new ModelMap("false");
27 }
28 return new ModelMap("true");
29 }
30
31
32 }
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.iyunv.com/files/rain-in-sun/springmvc-mybatis-atomikos.rar
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com