本文通过一个demo,介绍如何使用spring+hibernate+atomikos+tomcat构建在一个事务中涉及两个数据源的web应用。
demo功能:实现一个能成功提交和回滚的涉及两个数据库数据源的XA事务。
demo将实现:
1.一次性在两个数据库的两张表中各插入一条数据并提交。
2.一次性在两个数据库的两张表中各插入一条数据并回滚。
测试方式:restful web api
使用工具:
spring 4.1.1.RELEASE
hibernate 4.2.4.Final
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) );
create table 代码分析:
本项目使用spring框架,因此首先配置相关bean
1
2
9
11
12
13
14
15
16
17
18
20
21
22
23
24
25
26
27
28
29
30
31 select 1
32
33
34
35
36
37
38
40
41
42 ${qa.db.url}
43 ${qa.db.user}
44 ${qa.db.password}
45 true
46
47
48
49
50
51
52
53
55
56
57 ${dev.db.url}
58 ${dev.db.user}
59 ${dev.db.password}
60 true
61
62
63
64
65
67
68
69
70
71 org.hibernate.dialect.MySQL5InnoDBDialect
72 false
73 true
74 after_transaction
75
76
77
78
80
81
82
83
84 org.hibernate.dialect.MySQL5InnoDBDialect
85 false
86 true
87 after_transaction
88
89
90
91
92
94
95 true
96
97
98
99
100
101
102
104
105
106
107
108
109
110
111
112
113
114
115
其中qadataSource和devdataSource是对应两个数据库的数据源,qaSessionFactory和devSessionFactory是hibernate的sessionfactory。atomikosTransactionManager会自动管理两个atomikos的数据源的事务,即resource manager,atomikosUserTransaction为最上层的事务管理器为transaction manager。(关于RM和TM,请参见上篇博文)。
Model类如下:package com.xy.model
package com.xy.model;
import javax.persistence.*;
/**
* Created by helloworld on 2015/1/30.
*/
@Entity
@Table(name = "nameDev")
public class NameDev {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
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
1 package com.xy.model;
2
3
4 import javax.persistence.*;
5
6 /**
7 * Created by helloworld on 2015/1/30.
8 */
9 @Entity
10 @Table(name = "nameQa")
11 public class NameQa {
12 @Id
13 @GeneratedValue(strategy = GenerationType.AUTO)
14 private long id;
15 private String nameQa;
16
17 public long getId() {
18 return id;
19 }
20
21 public void setId(long id) {
22 this.id = id;
23 }
24
25 public String getNameQa() {
26 return nameQa;
27 }
28
29 public void setNameQa(String nameQa) {
30 this.nameQa = nameQa;
31 }
32 }
nameQa 处理事务的service
1 package com.xy.service;
2
3 import com.xy.model.NameDev;
4 import com.xy.model.NameQa;
5 import org.hibernate.SessionFactory;
6 import org.springframework.beans.factory.annotation.Autowired;
7 import org.springframework.stereotype.Service;
8 import org.springframework.transaction.annotation.Transactional;
9
10 /**
11 * Created by helloworld on 2015/1/30.
12 */
13 @Service
14 public class NameService {
15 @Autowired
16 private SessionFactory qaSessionFactory;
17 @Autowired
18 private SessionFactory devSessionFactory;
19
20 @Transactional(rollbackFor = Exception.class)
21 public void addQaAndDev(boolean hasException) throws Exception {
22 NameQa nameQa = new NameQa();
23 nameQa.setNameQa("hello");
24 qaSessionFactory.getCurrentSession().save(nameQa);
25
26 NameDev nameDev = new NameDev();
27 nameDev.setNameDev("hello");
28 devSessionFactory.getCurrentSession().save(nameDev);
29
30 if(hasException){
31 throw new Exception();
32 }
33
34 }
35
36
37 }
service 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 /**
13 * Created by helloworld on 2014/11/22.
14 */
15 @Controller
16 public class hibernateController {
17 @Autowired
18 NameService nameService;
19
20
21 @RequestMapping(value = "/addName", method = RequestMethod.POST)
22 ModelMap addName(@RequestParam("hasException") boolean hasException){
23 try {
24 nameService.addQaAndDev(hasException);
25 } catch (Exception e) {
26 e.printStackTrace();
27 return new ModelMap("false");
28 }
29 return new ModelMap("true");
30 }
31
32
33 }
controller 将项目打成war包,命名为test.war部署在tomcat上。
测试:
1.POST http://localhost:8080/test/addName.json
request parameters: hasException=false
返回:true 数据添加成功
2.POST http://localhost:8080/test/addName.json
request parameters: hasException=true
返回:false 两个数据库数据都未添加
源码下载:http://files.iyunv.com/files/rain-in-sun/springmvc-hibernate-atomikos.rar
运维网声明
1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网 享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com