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

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

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

分布式事务(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. 把excel导入到mysql中

    方法很多,不过建议你先看看mysql的开发文档,里面写的很详细的,如果你懒得看,可以看下面的 1.有个软件PHP Excel Parser Pro v4.2可以 2.可将Excel存成csv格式.然后 ...

  2. [vijos1891]学姐的逛街计划

                                                                     学姐的逛街计划 描述 doc 最近太忙了, 每天都有课. 这不怕, d ...

  3. 重装JDK后Tomcat和Eclipse的配置

    比如JDK之前是1.8.0_31的,升级之后变成了1.8.0_131之后,Tomcat需要做如下配置: 对于Eclipse中之前配置的Tomcat需要删除后重新添加一个.

  4. ubuntu安装ftp环境

    ubuntu安装ftp环境 安装: apt install vsftpd 启动: service vsftpd start 查看状态: service vsftpd status root登录: vi ...

  5. [Javascript] Link to Other Objects through the JavaScript Prototype Chain

    Objects have the ability to use data and methods that other objects contain, as long as it lives on ...

  6. vue - 官方 - 上手

    Vue和其它框架一样,有用CDN或本地JavaScript框架,国内我推荐 bootstrap cdn. 为什么很多人选择CDN呢? CDN:内容分发网络(不同区域不同服务器,更快),减少本地服务器压 ...

  7. easyui使用心得

    一.搭建easyui运行环境 1.下载easyui压缩文件 2.将降压后的文件添加至webapp目录下 3.引用5个必须的js和css文件  <!--引入easyui样式文件--> < ...

  8. Jenkins系列之-—03 修改Jenkins用户的密码

    一.Jenkins修改用户密码 Jenkins用户的数据存放在JENKINS_HOME/users目录. 1. 打开忘记密码的用户文件夹,里面就一个文件config.xml.打开并找到<pass ...

  9. Windows server 2003 + IIS6 搭建Asp.net MVC执行环境

    安装.Net Framework4.0. 下载地址: http://www.microsoft.com/zh-cn/download/details.aspx?id=17718  安装WindowsS ...

  10. Servlet第七课:ServletContext HttpSession 以及HttpServletRequest之间的关系

    课程目标: ① 在Servlet中懂得ServletContext HttpSession 以及HttpServletRequest之间的关系 ② 懂得怎样使用它们 概念介绍: 1. [共同点]不管对 ...