MySQL XA事务
MySQL从5.0.3开始支持分布式事务,当前的分布式事务只支持InnoDB存储引擎,在MySQL中,使用分布式事务的应用程序涉及一个或多个资源管理器和一个事务管理器。
- 资源管理器(Resource Manager):用于提供通向事务资源的途径,数据库服务器是一种资源管理器。该资源必须可以提交或回滚由RM管理的事务,例如,多态MySQL数据库作为多态资源管理器或者几台MySQL和几台Oracle作为资源管理器。
- 事务管理器(Transaction Manager):用于协调作为一个分布式事务的一部分的事务,TM与管理每个事务的RMs进行通信。在一个分布式事务中,各个单个事务均是分布式事务的“分支事务”。分布式事务和各分支通过一种命名方法进行标识。
用于执行分布式事务的过程使用两阶段提交协议,发生时间在由分布式事务的各个分支需要进行的行动已经执行之后。
- 在第一阶段,TM告知所有RM进行prepared操作,即所有RM被告知即将要执行commit操作,通常,这意味着用于管理分支的每个RM会记录对于被稳定保存的分支的行动,然后分支回答自己是否准备好进行commit操作了。
- 在第二阶段,TM告知所有RM进行commit或者回滚。如果在prepare时,有任一各RM回复说它无法进行commit操作,那么所有的RM将被告知进行回滚操作,否则所有的RM将被告知进行commit操作。
有些情况下,如果一个分布式事务只有一个RM,那么使用一阶段提交也可,即该RM会被告知同时进行prepare和commit操作。
XA事务语法
MySQL中与XA事务相关的SQL语句如下:
- XA {START|BEGIN} xid [JOIN|RESUME] #开始一个分布式事务
- XA END xid [SUSPEND [FOR MIGRATE]]
- XA PREPARE xid # 准备提交事务
- XA COMMIT xid [ONE PHASE] # 提交事务
- XA ROLLBACK xid #回滚事务
- XA RECOVER [CONVERT XID] # 查看处于PREPARE状态的事务
XID标识一个分布式事务,其组成:
- xid: gtrid [, bqual [, formatID ]]
- gtrid:必须,为字符串,表示全局事务标识符
- bqual:可选,为字符串,默认是空串,表示分支限定符
- formatID:可选,默认值为1,用于标识由gtrid和bqual值使用的格式
接下来拙劣地演示下这些语句的用法:
有一个user表有两个分片,分别在3306端口和3307端口的mysql上,灰色会3306上的操作,黑色为在3307上的操作,现在要从用户user1转50给user2:
在两个节点上分别开启事务:
XA事务状态(STATE)
1. 发起XA START后,事务置于ACTIVE STATE
2. 对于一个置于ACTIVE STATE的事务,可以发起多条SQL进行业务操作,然后发起XA END,使事务置于IDLE STATE
3. 对于一个置于IDLE STATE的事务,你可以发起XA PREPARE 或者XA COMMIT ... ONE PHASE语句
- XA PREPARE置事务于PREPARE STATE,告诉MySQL准备提交事务,可以用XA RECOVER语句来查看所有处于PREPARE STATE的事务
- XA COMMIT ... ONE PHASE告诉MySQL准备并提交(两个操作一起)事务
4. 对于一个置于PREPARE STATE的事务,可以发起XA COMMIT操作提交事务,或者发起XA ROLLBACK操作回滚事务
XA事务与LOCAL事务(LOCAL事务指非分布式事务,即以start transaction开始,以commit/rollback结束的事务),是互斥的,我们不能在一个LOCAL事务中间开启一个XA事务:
问题
之前看到书上说:MySQL的分布式事务是不完整的。如果分支事务在达到prepare状态时,数据库异常重新启动,重启后,可以继续对分支事务进行提交和回滚操作,但是提交的事务不会写入binlog,会导致:1.使用binlog恢复时丢失部分数据;2.如果存在slave,那么会导致slave和当前节点数据不一致的现象。我用5.7的MySQL试了一下,发现并不存在这个问题,主从依然能同步,不知道哪个版本开始修复了这个问题