此文已由作者夏昀授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。

分布式事务对性能有一定的影响,所以不是最佳的解决方案,能通过设计避免最好尽量避免。

分布式事务(Distributed transactions),也称作XA事务(XA是一个协议的名字),在spring中被称作global transaction,是指一个事务会涉及到不同的事务资源,比如不同的数据库,消息队列。事务资源都支持commit和rollback这样的事务控制命令。

按是否需要实现完整javaEE功能的应用服务器,可以将实现XA事务的方法分为两种:

1.一般情况下,XA事务是通过javaEE应用服务器实现的,即CMT(Container Managed Transaction)。应用服务器实现了JTA(Java Transaction API),应用通过JNDI获取应用服务器的JTA UserTransaction。JTA的api比较复杂,开发者需要研究较多JTA的细节,使用spring事务管理可以简化JTA的编程模型。但是这样还是需要依赖实现了对应javaEE功能的应用服务器。

2.不需要应用服务器(standalone),或者只需要轻量级的应用服务器,例如tomcat,tomcat没有实现所有的javaEE功能。在应用中加上支持jta的第三方包,例如atomikos,JOTM等。

分布式事务的结构如图所示:

图中,1表示APP与资源管理器RM之间的接口,是资源管理器的本地接口或者XA接口。如果使用事务管理器TM来管理分布式事务, 则不需要app直接调用rm,即1接口不会使用。 2表示app与TM的接口,即UserTransaction,这个接口和普通的事务管理接口类似,是一个有提交和回滚等操作的接口。使用该接口,就像事务只处理一个数据源一样。app通过该接口控制事务的提交或回滚。 3是TM与RM之间的接口,是一个两阶段提交(2 phase commit)的过程,两阶段提交简单的说就是一个数据源的事务要提交两次才算真正提交。该操作由TM控制,app不直接调用接口3。

下面通过一个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

 1  <?xml version="1.0" encoding="UTF-8"?>
  2 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3        xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context"
  4        xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
  5        xmlns:rabbit="http://www.springframework.org/schema/rabbit"
  6        xmlns:cache="http://www.springframework.org/schema/cache" xmlns:task="http://www.springframework.org/schema/task"
  7        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
  8        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">
  9     <context:component-scan base-package="com.xy">
 10         <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
 11     </context:component-scan>
 12     <context:property-placeholder location="classpath:context/database.properties"/>
 13     <tx:annotation-driven/>
 14 
 15     <bean id="abstractXADataSource" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init"
 16           destroy-method="close" abstract="true">
 17         <property name="xaDataSourceClassName" value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource"/>
 18         <property name="poolSize" value="10" />
 19         <property name="minPoolSize" value="10"/>
 20         <property name="maxPoolSize" value="30"/>
 21         <property name="borrowConnectionTimeout" value="60"/>
 22         <property name="reapTimeout" value="20"/>
 23         <!-- 最大空闲时间 -->
 24         <property name="maxIdleTime" value="60"/>
 25         <property name="maintenanceInterval" value="60"/>
 26         <property name="loginTimeout" value="60"/>
 27         <property name="testQuery">
 28             <value>select 1</value>
 29         </property>
 30     </bean>
 31     
 32     <bean id="qadataSource" parent="abstractXADataSource">
 33         <!-- value只要两个数据源不同就行,随便取名 -->
 34         <property name="uniqueResourceName" value="mysql/sitestone1" />
 35         <property name="xaDataSourceClassName"
 36                   value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
 37         <property name="xaProperties">
 38             <props>
 39                 <prop key="URL">${qa.db.url}</prop>
 40                 <prop key="user">${qa.db.user}</prop>
 41                 <prop key="password">${qa.db.password}</prop>
 42                 <prop key="pinGlobalTxToPhysicalConnection">true</prop>
 43             </props>
 44         </property>
 45     </bean>
 46 
 47     <bean id="devdataSource" parent="abstractXADataSource">
 48         <!-- value只要两个数据源不同就行,随便取名 -->
 49         <property name="uniqueResourceName" value="mysql/sitestone" />
 50         <property name="xaDataSourceClassName"
 51                   value="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" />
 52         <property name="xaProperties">
 53             <props>
 54                 <prop key="URL">${dev.db.url}</prop>
 55                 <prop key="user">${dev.db.user}</prop>
 56                 <prop key="password">${dev.db.password}</prop>
 57                 <prop key="pinGlobalTxToPhysicalConnection">true</prop>
 58             </props>
 59         </property>
 60     </bean>
 61 
 62 
 63 
 64     <bean id="qasqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 65         <property name="dataSource" ref="qadataSource" />
 66         <property name="mapperLocations" value="classpath*:com/xy/dao/*.xml" />
 67     </bean>
 68 
 69     <bean id="devsqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
 70         <property name="dataSource" ref="devdataSource" />
 71         <property name="mapperLocations" value="classpath*:com/xy/daodev/*.xml" />
 72     </bean>
 73 
 74     <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
 75           init-method="init" destroy-method="close">
 76         <property name="forceShutdown">
 77             <value>true</value>
 78         </property>
 79     </bean>
 80     <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
 81         <property name="transactionTimeout" value="300" />
 82     </bean>
 83 
 84     <bean id="transactionManager"
 85           class="org.springframework.transaction.jta.JtaTransactionManager">
 86         <property name="transactionManager">
 87             <ref bean="atomikosTransactionManager"/>
 88         </property>
 89         <property name="userTransaction">
 90             <ref bean="atomikosUserTransaction"/>
 91         </property>
 92         <!-- 必须设置,否则程序出现异常 JtaTransactionManager does not support custom isolation levels by default -->
 93         <property name="allowCustomIsolationLevels" value="true"/>
 94 
 95     </bean>
 96 
 97 
 98 
 99     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">100         <property name="basePackage" value="com.xy.dao"/>101         <property name="sqlSessionFactoryBeanName" value="qasqlSessionFactory" />102     </bean>103 
104     <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">105         <property name="basePackage" value="com.xy.daodev"/>106         <property name="sqlSessionFactoryBeanName" value="devsqlSessionFactory" />107     </bean>108 </beans>

其中qadataSource和devdataSource是对应两个数据库的数据源,qasqlSessionFactory和devsqlSessionFactory是mybatis的sessionfactory,两个MapperScannerConfigurer自动将不同数据源的sql语句文件与interface自动装配起来,atomikosTransactionManager会自动管理两个atomikos的数据源的事务,即resource manager,atomikosUserTransaction为最上层的事务管理器为transaction manager。

网易云免费体验馆,0成本体验20+款云产品!

更多网易技术、产品、运营经验分享请点击

相关文章:
【推荐】 MySQL之不得不说的keepsync和trysync

spring分布式事务学习笔记(1)的更多相关文章

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

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

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

    此文已由作者夏昀授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. Model类如下:package com.xy.model 1 package com.xy.model;   ...

  3. Spring 源码学习笔记11——Spring事务

    Spring 源码学习笔记11--Spring事务 Spring事务是基于Spring Aop的扩展 AOP的知识参见<Spring 源码学习笔记10--Spring AOP> 图片参考了 ...

  4. Spring 源码学习笔记10——Spring AOP

    Spring 源码学习笔记10--Spring AOP 参考书籍<Spring技术内幕>Spring AOP的实现章节 书有点老,但是里面一些概念还是总结比较到位 源码基于Spring-a ...

  5. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  6. spring cloud(学习笔记)高可用注册中心(Eureka)的实现(二)

    绪论 前几天我用一种方式实现了spring cloud的高可用,达到两个注册中心,详情见spring cloud(学习笔记)高可用注册中心(Eureka)的实现(一),今天我意外发现,注册中心可以无限 ...

  7. Spring分布式事务实现概览

    分布式事务,一直是实现分布式系统过程中最大的挑战.在只有单个数据源的单服务系统当中,只要这个数据源支持事务,例如大部分关系型数据库,和一些MQ服务,如activeMQ等,我们就可以很容易的实现事务. ...

  8. Spring分布式事务

    [如何实现XA式.非XA式Spring分布式事务] [http://www.importnew.com/15812.html] 在JavaWorld大会上,来自SpringSource的David S ...

  9. Mysql事务学习笔记

    Mysql事务学习笔记 1.事务概述 事务是数据库的执行单元,它包含了一条或多条sql语句,进行的操作是要么全部执行,要么全部都不执行. 2.事务执行命令 语法格式: start transactio ...

随机推荐

  1. 《effective C++》:条款37——绝不重新定义继承而来的缺省参数值

    引子: 阿里的一道题: #include <IOSTREAM> using namespace std; class A{ public: ) { cout<<"a~ ...

  2. PHP 基础复习 2018-06-17

    (1)AJAX Asynchronous JavaScript And XML(异步 JavaScript 及 XML) (2)创建 XMLHttpRequest 对象 不同的浏览器使用不同的方法来创 ...

  3. python学习之-- 事件驱动模型

    目前主流的网络驱动模型:事件驱动模型 事件驱动模型:也属于生产者/消费者结构,通过一个队列,保存生产者触发的事件,队列另一头是一个循环从队列里不断的提取事件.大致流程如下:1:首先生成一个事件消息队列 ...

  4. OO第三单元总结--根据JML写代码

    一. JML语言 1. 理论基础 首先,JML不是JAVA的一部分,它是一群研究者为JAVA设计的扩展部分,但还没有得到官方的支持.因此,JAVA编译器并不支持JML,所以要想JML起作用,只能采用类 ...

  5. 利用WiFi Pineapple Nano渗透客户端获取SHELL

    前言: 前两篇文章介绍了The WiFi Pineapple Nano设备的一些主要功能模块,例如PineAP.SSLsplit和Ettercap等.今天给大家实际场景演示下如何利用Pineapple ...

  6. 破解电信光猫华为HG8120C关闭路由功能方法

    昨天电信的工作人员来安装了电信的光纤宽带,使用的是华为HG8120C这款光电转换器与路由器一体机 这导致下级路由无法直接使用PPPOE拨号连接到互联网,且无法使用端口映射来实现外网访问 而华为开放给用 ...

  7. 如何扩展ArcGIS中的元数据编辑器

    http://www.esrichina-bj.cn/old../library/arcnews16/Metadata.htm http://www.esrichina-bj.cn/old../lib ...

  8. Spark SQL数据载入和保存实战

    一:前置知识具体解释: Spark SQL重要是操作DataFrame,DataFrame本身提供了save和load的操作. Load:能够创建DataFrame. Save:把DataFrame中 ...

  9. CentOS 6.x Radius

    CentOS 6.x Radius 一.   实现环境: 1.系统:CentOS  release  6.6 (Final) 2.需要软件包: 1) freeradius-2.1.12-6.e16.x ...

  10. DWR(AJAX)+Highcharts绘制曲线图,饼图

    基本需求: 1. 在前台会用DWR框架(或者AJAX)调用Java后台代码获取要在Hightcharts展示的数据 2. 了解JSON(JavaScript Object Notation)的格式 3 ...