Mysql分布式事务

  • XA协议
    • 分布式事务模型
    • 流程
    • 两阶段提交
  • Mysql中的XA语法
    • 使用演示
    • XA状态转换图
  • XA的BUG
  • XA的性能问题
  • 总结
  • 参考资源

XA协议

为了规范分布式事务的管理,X/OPEN 提出了分布式事务处理规范XA协议,XA规范了TM与RM之间的通信接口,在TM与多个RM之间形成一个双向通信桥梁,从而在多个数据库资源下保证ACID四个特性。目前知名的数据库,如Oracle, DB2,mysql等,都是实现了XA接口的,都可以作为RM。

XA是数据库的分布式事务,强一致性,在整个过程中,数据都处于被锁住的状态,即从prepare到commit、rollback的整个过程中,TM一直拥有参与分布式事务RM对应的数据库的锁,如果有其他人要修改数据库的该条数据,就必须等待锁的释放,存在长事务风险。


分布式事务模型

X/Open定义了分布式事务处理模型,包括应用程序AP、事务管理器TM、资源管理器RM、通信资源管理器CRM。


在XA规范中分布式事务有AP、RM、TM组成:

  • 应用程序(Application Program):定义事务边界(定义事务开始和结束)并访问事务边界内的资源
  • 资源管理器(Resource Manager):RM管理计算机共享的资源,资源包含比如数据库、文件系统等
  • 事务管理器(Transaction Manager,简称TM):负责管理全局事务,分配事务唯一标识,监控事务的执行进度,并负责事务的提交、回滚、失败恢复等。

流程

分布式事务的基本流程如下:


具体流程如下:

  1. 配置TM,将RM注册到TM
  2. AP从TM获取资源管理器的代理,获取TM所管理的RM的JDBC连接
  3. AP向TM发起全局事务
  4. TM将XID通知到各RM
  5. AP通过Connection连接直接对RM进行操作
  6. AP结束全局事务
  7. TM会通知RM全局事务结束
  8. 开始二阶段提交

两阶段提交

当每个RM都结束了全局事务的执行后,此时每个RM管理的分布式事务分支还没有提交,只是把该事务管理的业务逻辑执行完了。

进入二阶段提交阶段,在这个阶段,会先进入prepare阶段,然后再是commit或者rollback阶段。

具体流程如图:


第一阶段分为两个步骤:

  • 事务管理器通知参与该事务的各个资源管理器,通知他们开启事务、执行SQL(暂不提交),并进入prepare状态(该状态下可执行commit/ rollback)。
  • 资源管理器接收到消息后开始准备阶段,写好事务日志并执行事务,但不提交,然后将是否就绪的消息返回给事务管理器
  • RM根据自己的情况,如果判断自己进行的工作可以被提交,那就就对工作内容进行持久化,并给TM回执OK;否者给TM的回执NO
  • RM在发送了否定答复并回滚了已经的工作后,就可以丢弃这个事务分支信息了

第二阶段也分为两个步骤:

  • 事务管理器在接受各个消息后,开始分析,如果有任意其一失败,则发送回滚命令,否则发送提交命令。
  • 各个资源管理器接收到命令后,执行(耗时很少),并将提交消息返回给事务管理器。

两阶段提交的好处是有了事务管理器进行统一管理,让事务在提交前尽可能的完成所有能完成的工作。同时两阶段提交可以保证事务的一致性,不管是事务管理器还是各个资源管理器,每执行一步操作都会被日志记录,为出现故障后的恢复提供依据。


Mysql中的XA语法

Mysql中分布式操作的基本模板如下:

开启xa事务,XA start <xid>
DML语句,即SQL增删改查语句
终止XA事务,XA end <xid>
预提交事务, XA prepare <xid>,这一步是有返回值的
提交,XA commit <xid>,根据prepare操作的返回结果做的处理
回滚,XA rollback <xid>,根据prepare操作的返回结果做的处理
XA RECOVER: 返回当前数据库中处于PREPARE状态的分支事务的详细信息

每个事务必须有一个唯一的xid值,因此当前值不能被其他XA事务使用,xid是一个XA事务标识符,用来唯一标识一个分布式事务。

xid值可以由客户端提供,或者由Mysql服务器生成。

xid基本格式如下:

xid: gtrid [,bqual] [, formatID]
  • gtrid 是一个分布式事务标识符,相同的分布式事务使用相同的gtrid,这样可以明确知道XA事务属于哪一个分布式事务
  • bqual是一个分支限定符,默认为空串,对于一个分布式事务中的每个分支事务,bqual必须是唯一的
  • formatID是一个数字,用于标识由gtrid和bqual值使用的格式,默认为1

XA语法中用到的xid值都必须和START操作使用的xid值相同


使用演示


上面给出的是命令行方式的演示过程,下面再给出java代码的使用过程:

    public MysqlXADataSource xaDataSource(String url,String uname,String pwd){MysqlXADataSource xa = new MysqlXADataSource();xa.setUrl(url);xa.setUser(uname);xa.setPassword(pwd);return xa;}@Testpublic void testXA(){MysqlXADataSource testXA = xaDataSource("jdbc:mysql://xxx:3306/test", "root", "xxx");MysqlXADataSource trainingXA = xaDataSource("jdbc:mysql://xxx:3306/training", "root", "xxx");try {//获取每个分支事务的连接XAConnection test = testXA.getXAConnection();XAResource testXAResource = test.getXAResource();Connection testConn= test.getConnection();Statement testStatement = testConn.createStatement();XAConnection train = trainingXA.getXAConnection();XAResource trainXAResource = train.getXAResource();Connection trainConn = train.getConnection();Statement trainStatement = trainConn.createStatement();//生成每个分支事务对应的XIDMysqlXid testXid = new MysqlXid("test".getBytes(StandardCharsets.UTF_8), "testDB".getBytes(StandardCharsets.UTF_8), 1);MysqlXid trainXid = new MysqlXid("test".getBytes(StandardCharsets.UTF_8), "trainDB".getBytes(StandardCharsets.UTF_8), 1);//事务分支1关联分支事务sql语句testXAResource.start(testXid,XAResource.TMNOFLAGS);testStatement.execute("UPDATE stu SET classId=3 WHERE id=1");testXAResource.end(testXid,XAResource.TMSUCCESS);//事务分支2关联分支事务sql语句trainXAResource.start(trainXid,XAResource.TMNOFLAGS);trainStatement.execute("UPDATE Salers SET SNO=\"123\" WHERE SNAME=\"123\"");trainXAResource.end(trainXid,XAResource.TMSUCCESS);//两阶段提交协议第一阶段int testRes = testXAResource.prepare(testXid);int trainRes = trainXAResource.prepare(trainXid);//两阶段提交协议第二阶段if(XAResource.XA_OK==testRes && XAResource.XA_OK==trainRes){//存储引擎级别事务提交testXAResource.commit(testXid,false);trainXAResource.commit(trainXid,false);}else {testXAResource.rollback(testXid);trainXAResource.rollback(trainXid);}} catch (SQLException | XAException e) {e.printStackTrace();}}

上面代码中出现了一些XAResource标记,这里解释一下:

  • XAResource#start方法开启一个分支事务

下面提到的名词都是XAResource类中的常量,分别对应一个整数值

XAResource:
void start(Xid xid, int flags) throws XAException;

如果这里标记传入的是TMJOIN,会尝试去加入上一个被RM记录的事务中去。如果TMRESUME被设置了,会尝试去恢复xid与自己相同的并且是被挂起的事务分支。

如果没有设置上面两个标记,并且还找到了一个分支事务并且该分支事务xid与自己相同,那么会抛出异常

一般无特殊情况推荐使用TMNOFLAGS,表示不设置任何标志


  • XAResource#end方法结束当前分支事务的执行
XAResource:
void end(Xid xid, int flags) throws XAException;

这里标记的设置分为了三种情况:

  • TMSUCCESS: 该分支事务已经成功完成了
  • TMFAIL: 该分支事务执行失败,RM会标记当前事务为回滚状态
  • TMSUSPEND: 会将当前分支事务临时挂起进入未完成状态,当前事务被挂起后需要通过start方法设置TMRESUME来恢复

  • XAResource#commit方法提交当前分支事务
XAResource:
void commit(Xid xid, boolean onePhase) throws XAException;

onePhase标志是否为一阶段提交,两阶段提交协议中,如果只有一个RM参与,那么可以优化为一阶段提交。

相当于跳过了prepare一阶段提交,变成了局部事务的处理方式


XA状态转换图



XA的BUG

在Mysql 5.5之前的版本中,如果分支事务到达prepare状态,此时数据库异常重启后,可以选择对分支事务进行提交或者回滚,但是即使选择提交事务,该事务也不会被写入BINLOG日志,这会导致在使用BINLOG恢复数据时,丢失部分数据,并在如果存在从库,可能导致主从数据库的数据不一致。

此外,如果是分支事务的客户端连接异常终止的话,例如执行prepare之后退出连接,那么数据库会自动回滚未完成的事务,之所以这样做是因为对于prepare的事务,MySQL 是不会记录binlog的(官方说是减少fsync, 起到了优化的作用)。只有当分布式事务提交的时候才会把前面的操作写入binlog信息,所以对于binlog来说,分布式事务与普通的事务没有区别,而prepare以
前的操作信息都保存在连接的I0 CACHE中,如果这个时候客户端退出了,以前的binlog信息都会被丢失,再次重连后允许提交的话,会造成Binlog丢失,从而造成主从数据的不一致,所以官方在客户端退出的时候直接把已经prepare的事务都回滚了!

但是如果分布式事务情况下,其他分支事务都成功提交,这个分支回滚,会导致分布式事务的不完整,丢失部分分支事务内容。

MySql 5.7中做了以下优化: 在session断开和实例崩溃的情况下,事务都不会自动回滚,同时在XA PREPARE时,之前的事务信息就会被写入到BINLOG并同步到从库,最终再由用户决定事务回滚或者提交。


XA的性能问题

  • XA事务和本地事务以及锁表操作是互斥的,因为XA事务会锁住当前表
  • 开启了xa事务就无法使用本地事务和锁表操作
  • 开启了本地事务就无法使用xa事务

总结

1)在执行分支事务时,会将RM资源锁住,需要等到所有的RM响应,等到第二阶段执行完毕时(提交/回滚),RM的锁才会释放,在高并发场所不适用。

2)XA方案依赖于本地数据库对XA协议的支持,如果本地数据库不支持XA协议那么第三方程序(Java)将操作不了。例如许多非关系型数据库并没有支持XA。

3)MySQL对XA方案支持的不太友好,MySQL的XA实现,没有记录prepare阶段日志。


参考资源

数据库系列之MySQL分布式事务原理及实现

对XA协议的认识

《分布式事务系列教程-第四章-XA分布式事务解决方案》

mysql2阶段提交具体实现_深入理解二阶段提交协议(DDB对XA悬挂事务的处理分析)(一)…

分布式事务实战—XA两阶段提交(2PC)方案详解

书籍: 深入浅出MySQL,高性能MySQL,Innodb技术内幕

Mysql分布式事务相关推荐

  1. MySQL分布式事务(XA事务)

    MySQL分布式事务(XA事务) 官网:https://dev.mysql.com/doc/refman/5.7/en/xa.html 1.什么是分布式事务 分布式事务就是指事务的参与者.支持事务的服 ...

  2. jta mysql_JTA 使用 MySQL 分布式事务

    假定在MySQL实例1上有表 create table person( id int, name varchar(32) ) MySQL实例2上也有一张同样的表,现在从实例1中的 person 表中删 ...

  3. 深入理解PHP+Mysql分布式事务与解决方案

    事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元: 事务的ACID特性 事务应该具有4个属性:原子性.一致性.隔离性.持续性 原子性(atomicity).一个事务是 ...

  4. 详解Mysql分布式事务XA

    在开发中,为了降低单点压力,通常会根据业务情况进行分表分库,将表分布在不同的库中(库可能分布在不同的机器上).在这种场景下,事务的提交会变得相对复杂,因为多个节点(库)的存在,可能存在部分节点提交失败 ...

  5. java mysql 分布式事务_java事务(三)——自己实现分布式事务

    在上一篇<java事务(二)--本地事务>中已经提到了事务的类型,并对本地事务做了说明.而分布式事务是跨越多个数据源来对数据来进行访问和更新,在JAVA中是使用JTA(Java Trans ...

  6. mysql分布式事务wcf_WCF系列_分布式事务(下)

    1.WCF分布式事务例子 这里也用转账的例子说事. 用户在系统A和系统B都有账户,账户间的资金可以互转,系统A的资金减少多少,系统B的相应账户的资金就增加多少. 系统A机器上有数据库AccountA, ...

  7. mysql分布式事务wcf_[转载]WCF系列_分布式事务(下)

    浏览到chnking的WCF的分布式事务处理不错,转载过来分享一下.1. WCF分布式事务例子这里也用转账的例子说事. 用户在系统A和系统B都有账户,账户间的资金可以互转,系统A的资金减少多少,系统B ...

  8. mysql平台workb_MySQL分布式事务

    一.分布式事务 在说分布式事务(XA)之前,可以先看一下"以交易系统为例,看分布式事务架构的五大演进",阐述了分布式事务解决了什么问题? InnoDB存储引擎提供了对XA事务的支持 ...

  9. MySQL中基于XA实现的分布式事务

    文章目录 一.前言 二.XA基础 2.1 XA基础知识 2.1.1 DTP是什么? 2.1.2 DTP的结构:AP TM RM(重点001) 2.1.3 DTP的重要概念 2.2 XA事务:基于两阶段 ...

最新文章

  1. java random构造方法_Java中的Random()函数及两种构造方法
  2. HDU 2534 Score
  3. opencv机器学习线性回归_全面讲解手推实战机器学习之线性回归
  4. ant design select 坑总结
  5. CTF Crypto(密码学)总结
  6. 【数据结构作业—01】用单循环链表解决约瑟夫问题
  7. django按钮点击后想刷新当前页面的view写法
  8. 大学计算机在线阅读,大学计算机基础作业与答案.doc
  9. 七 web爬虫讲解2—urllib库爬虫—状态吗—异常处理—浏览器伪装技术、设置用户代理...
  10. C# aspx页面动态加载ascx用户控件 及 利用反射调用其内方法
  11. 输出该数二进制表示中1的个数。求取十进制数字元素1的个数 (3种方法)
  12. 山西台达plc可编程控制器_可编程控制器2(PLC)控制原理
  13. Hybrid框架UI重构之路:一、师其长技以自强
  14. 利用级数求和推导泊松分布的期望方差
  15. SpringBoot properties和yml的区别
  16. java 6 基础_java基础(6)
  17. 小学生十大计算机专业书排行,小学教辅十大排行榜2018 小学教辅书那些比较好...
  18. 高版本Matlab运行时//在当前文件夹或MATLAB路径中未找到文件//函数或变量 ‘xx‘ 无法识别//解决方法
  19. APE转MP3的转换码率说明
  20. 中文乱码问题—字符集utf8、uf8mb4与排序规则

热门文章

  1. 【790. 多米诺和托米诺平铺】
  2. python抢购火车票源代码_100行Python代码实现自动抢火车票(附源码)
  3. 【NetApp】hot spare盘数量的官方推荐
  4. csdn如何设置免费皮肤
  5. RT-Thread笔记 之 编程风格
  6. 短信接口安全防御策略
  7. UIButton高光状态(highlighted)时阴影效果
  8. 用计算机参加关于动漫的工作计划,动漫社团活动工作计划范文
  9. 《Python专栏 知识图谱导航》有勇气的牛排
  10. 【ProgrammingMicrosoftAzureServiceFabric】第四章: Actor模式