Mysql分布式事务

Mysql分布式事务

Mysql分布式事务

为了规范分布式事务的管理,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):负责管理全局事务,分配事务唯一标识,监控事务的执行进度,并负责事务的提交、回滚、失败恢复等。

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

具体流程如下:

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

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

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

    具体流程如图:

    第一阶段分为两个步骤:

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

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

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

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

    Mysql中的XA语法

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

    开启xa事务,XA start DML语句,即SQL增删改查语句终止XA事务,XA end 预提交事务, XA prepare ,这一步是有返回值的提交,XA commit ,根据prepare操作的返回结果做的处理回滚,XA rollback ,根据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; } @Test public 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(); //生成每个分支事务对应的XID MysqlXid 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阶段日志。

    原文链接:blog.csdn.net/m0_53157173/article/details/125275556?utm_source=tuicool&utm_medium=referral

    郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
    (0)
    用户投稿
    上一篇 2022年6月17日
    下一篇 2022年6月17日

    相关推荐

    • csgo连跳小操作

      csgo连跳指令参数bind “MWHEELDOWN” “+jump”。要连跳的话跳跃键“空格”改成“鼠标滚轮”。先“w”,然后“滚…

      2022年8月10日
    • 10岁了还和大人一起睡,发生了什么?

      #我要上头条# #育儿# 关于土豆睡觉这件事,早在2年前,我就专门写过一篇分房睡的文章:我决定了!让读小学的儿子搬回来和我们一起睡 从那个时候开始,我家基本上就维持2张大床拼床的状…

      2022年9月18日
    • 没带卡怎么在ATM机取款(无卡取款怎么操作)

      刷脸消费支付已经十分方便,最近不少银行根据这种刷脸技术,提供了刷脸存取款的业务。我们不需要带卡,就可以直接刷脸取款。下面让我们来看看具体怎么操作。 刷脸取款怎么操作? 【1】我们找…

      2022年11月17日
    • 三个技巧帮你:想变美,不怕疼

      很多美宝们做项目的时候,想要好的治疗效果,却又怕疼 比如在做水光项目时,有手针、机打和无针 注射疼痛感依次减少,但补水效果也是依次降低的,有的人因为怕疼而选择无针水光不仅效果打折扣…

      2022年5月19日
    • 马玉琴夫妇真实感情状态被曝光,熟人:俩人互相嫌弃、各玩各的

      随着短视频平台的迅猛发展,不少普通人凭借这个平台,吸引了数以万计的粉丝关注,成为网上小有名气的网红,并成功将流量套现,实现财富自由的梦想。马玉琴和李玉成这对夫妇,因为有着32岁的年…

      2022年6月8日
    • 楼市承压,房价低迷的特殊阶段,对中国城市价值的一次复盘思考

      这是熊猫贝贝的第1204篇原创文章: #哪个二线城市房产最保值# 近日,中国中信集团有限公司主管、中国证券市场研究设计中心主办的财经类杂志周刊《财经》在各个互联网资讯平台发布了一篇…

      2022年8月4日
    • 伊万卡特朗普才不是“花瓶”,小西装礼服裙,走到哪都万分显眼

      伊万卡特朗普可谓是国际上最知名的女企业家,她有颜有才还有钱,在绝大多数人眼中,她就是独一无二的存在。 作为顶级名流,她的睿智和聪慧完全打破了“花瓶”一说,这一点在她家财万贯的家底中…

      2022年8月24日
    • EDG、LNG败者组大战,LPL多项里程碑回顾,RNG成就最强击杀小队

      2022年LPL夏季赛季后赛败者组EDG对阵LNG将在今天17点进行,EDG能否复刻去年夏天的神奇非常值得期待,而LNG的黑马之旅会在此终结吗?此外,LPL官方也公布了今年夏季赛选…

      2022年8月26日
    • 淘宝双十一喵果怎么组队(淘宝双十一领喵币攻略)

      随着双十一大促开启,大家对今年淘宝天猫双十一推出的喵果赢红包的活动非常感兴趣。与往年一样,用户也是需要通过组队来进行PK赢红包的。那么,淘宝双十一喵果怎么组队?双十一喵果组队都有哪…

      2022年10月26日
    • 私有云搭建(私有云平台搭建)

      但想要搭建私有云可不是那么简单的,需要投入大量的金钱人力技术才行然而大部分的中小型企业都属于腰部企业,投入大量资金去搭建一个私有云平台就会显得投入产出比不合理这也是为什么中小企业数…

      2022年11月9日

    联系我们

    联系邮箱:admin#wlmqw.com
    工作时间:周一至周五,10:30-18:30,节假日休息