本文通过一个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为

 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) );

create table

代码分析:

本项目使用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:property-placeholder file-encoding="UTF-8" ignore-resource-not-found="true"
location="classpath*:context/database.properties"/>
<context:component-scan base-package="com.xy">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<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/sitestone" />
<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/sitestone1" />
<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="qaSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="packagesToScan" value="com.xy.model"/>
<property name="dataSource" ref="qadataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.autoReconnect">true</prop>
<prop key="hibernate.connection.release_mode">after_transaction</prop>
</props>
</property>
</bean>
<bean id="devSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="packagesToScan" value="com.xy.model"/>
<property name="dataSource" ref="devdataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.autoReconnect">true</prop>
<prop key="hibernate.connection.release_mode">after_transaction</prop>
</props>
</property>
</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> </beans>

其中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

 package com.xy.model;

 import javax.persistence.*;

 /**
* Created by helloworld on 2015/1/30.
*/
@Entity
@Table(name = "nameQa")
public class NameQa {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
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

处理事务的service

 package com.xy.service;

 import com.xy.model.NameDev;
import com.xy.model.NameQa;
import org.hibernate.SessionFactory;
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
private SessionFactory qaSessionFactory;
@Autowired
private SessionFactory devSessionFactory; @Transactional(rollbackFor = Exception.class)
public void addQaAndDev(boolean hasException) throws Exception {
NameQa nameQa = new NameQa();
nameQa.setNameQa("hello");
qaSessionFactory.getCurrentSession().save(nameQa); NameDev nameDev = new NameDev();
nameDev.setNameDev("hello");
devSessionFactory.getCurrentSession().save(nameDev); if(hasException){
throw new Exception();
} } }

service

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 hibernateController {
@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包,命名为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.cnblogs.com/files/rain-in-sun/springmvc-hibernate-atomikos.rar

使用spring+hibernate+atomikos+tomcat构建分布式事务的更多相关文章

  1. 使用spring+mybatis+atomikos+tomcat构建分布式事务

    本文通过一个demo,介绍如何使用spring+mybatis+atomikos+tomcat构建在一个事务中涉及两个数据源的web应用. demo功能:实现一个能成功提交和回滚的涉及两个数据库数据源 ...

  2. Spring Cloud Alibaba | 微服务分布式事务之Seata

    Spring Cloud Alibaba | 微服务分布式事务之Seata 本篇实战所使用Spring有关版本: SpringBoot:2.1.7.RELEASE Spring Cloud:Green ...

  3. Spring3.0+Hibernate+Atomikos集成构建JTA的分布式事务--解决多数据源跨库事务

    一.概念 分布式事务分布式事务是指事务的参与者.支持事务的服务器.资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上.简言之,同时操作多个数据库保持事务的统一,达到跨库事务的效果. JTA ...

  4. 【分布式事务】使用atomikos+jta解决分布式事务问题

    一.前言 分布式事务,这个问题困惑了小编很久,在3个月之前,就间断性的研究分布式事务.从MQ方面,数据库事务方面,jta方面.近期终于成功了,使用JTA解决了分布式事务问题.先写一下心得,后面的二级提 ...

  5. 【分布式事务】spring cloud集成lcn解决分布式事务

    参考地址:https://blog.csdn.net/u010882691/article/details/82256587 参考地址:https://blog.csdn.net/oyh1203/ar ...

  6. Spring Boot 集成 Seata 解决分布式事务问题

    seata 简介 Seata 是 阿里巴巴2019年开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务.在 Seata 开源之前,Seata 对应的内部版本在阿里内部一 ...

  7. Spring Cloud Alibaba学习笔记(14) - Spring Cloud Stream + RocketMQ实现分布式事务

    发送消息 在Spring消息编程模型下,使用RocketMQ收发消息 一文中,发送消息使用的是RocketMQTemplate类. 在集成了Spring Cloud Stream之后,我们可以使用So ...

  8. spring分布式事务学习笔记

    最近项目中使用了分布式事务,本文及接下来两篇文章总结一下在项目中学到的知识. 分布式事务对性能有一定的影响,所以不是最佳的解决方案,能通过设计避免最好尽量避免. 分布式事务(Distributed t ...

  9. spring分布式事务学习笔记(1)

    此文已由作者夏昀授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 分布式事务对性能有一定的影响,所以不是最佳的解决方案,能通过设计避免最好尽量避免. 分布式事务(Distrib ...

随机推荐

  1. HDU 4489 The King’s Ups and Downs (DP+数学计数)

    题意:给你n个身高高低不同的士兵.问你把他们按照波浪状排列(高低高或低高低)有多少方法数. 析:这是一个DP题是很明显的,因为你暴力的话,一定会超时,应该在第15个时,就过不去了,所以这是一个DP计数 ...

  2. 为什么要坚持用ASP.NET MVC!(②)

    尽管ASP.NET MVC架构和Web Form架构区别很大,但是还是有很多共同之处.毕竟它们都是以ASP.NET API与.NET框架为基础构建的.比较一下ASP.NET MVC和Web Form框 ...

  3. javascript --执行上下文,作用域

    执行上下文 顾名思意就知道他是动态的,只在代码运行的时候产生 作用域 顾名思意就知道它是一个"领域",并且这个"领域"在一开始就规划好, 不会在改, var d ...

  4. 音频视频播放(jquery中将jquery方法转化成js方法)

    在jQuery中没有音频视频直接播放的方法,我们在写音频视频时,应该将jquery的方法转化为js方法:play():pause() 补充:   将jq对象转化成js对象写法: var music=$ ...

  5. contiki-main.c 一 打印观察 <contiki学习之五>

    说明: 本文依赖于 contiki/platform/native/contiki-main.c 文件. 在项目工程目录下的hello-world.c 文件里面,有许多的宏,但没有最关键的main() ...

  6. Python写的东西在CMD下打印中文

    以前遇到的问题是在IDLE中可以print出中文,在cmd却是乱码. 后来想明白,IDLE中默认编码是unicode,而cmd中是ANSI,即cp963,即GBK 所以这样就能输出中文了: s = “ ...

  7. C#制作在线升级程序

    //这是一个webservice private AppUpdate.UpdateServ UpdateSvr; private void button1_Click(object sender, S ...

  8. ListView删除选中的多项目

    //ListView删除选中的多项目function DeleteMultSelItems(ListView:TListView):Boolean;var  I: Integer;begin  Res ...

  9. java 覆盖hashCode()深入探讨 代码演示样例

    java 翻盖hashCode()深入探讨 代码演示样例 package org.rui.collection2.hashcode; /** * 覆盖hashcode * 设计HashCode时最重要 ...

  10. [GIF] The Phase Property in GIF Loop Coder

    In this lesson, we look at one of the most powerful features in GIF Loop Coder, the phase property, ...