参考https://dev.mysql.com/doc/refman/8.0/en/xa.html

简介

RM与TM角色

资源管理器(RM):提供对事务性资源的访问。数据库服务器是一种资源管理器。必须能够提交或回滚由RM管理的事务。XA的MySQL实现使MySQL服务器能够充当资源管理器,在全局事务中处理XA事务。

事务管理器(TM):协调作为全局事务一部分的事务。它与处理每个事务的RMs通信。全局事务中的单个事务是全局事务的“分支”。全局事务及其分支由后面描述的命名方案标识。连接到MySQL服务器的客户机程序充当事务管理器。

two-phase commit(2PC)

1.first phase:在第一阶段,准备好所有分支。也就是说,他们被告知由TM准备提交。通常,这意味着管理分支的每个RM都会在稳定存储中记录分支的操作。分支表示它们是否能够做到这一点,这些结果将用于第二阶段。

2.second phase:TM告诉RMs是提交还是回滚。如果所有分支在准备就绪时都指示它们能够提交,则会通知所有分支提交。如果任何分支在准备时指出它无法提交,那么所有分支都会被告知回滚。

例外

有时候,XA事务(全局事务)可能会使用one-phase commit(1PC)。比如当全局事务管理器发现全局事务只包含一个事务资源的时候,那个资源将被告知同时运行prepare、commit

语法

xid的组成: gtrid [, bqual [, formatID ]] gtrid:全局事务标识符; bqual:分支标识符 formatID:标识gtrid和bqual值使用的格式的数字 如语法所示,bqual和formatID是可选的。如果未给定,则默认bqual值为“”。如果未给定,则默认formatID值为1

  1. XA {START|BEGIN} xid [JOIN|RESUME]
  2. XA END xid [SUSPEND [FOR MIGRATE]]
  3. XA PREPARE xid
  4. XA COMMIT xid [ONE PHASE]
  5. XA ROLLBACK xid
  6. XA RECOVER [CONVERT XID]

注意事项

gtrid和bqual必须是字符串文字,每个文字的长度都不能超过64字节(不是字符)。gtrid和bqual可以用几种方式指定。可以使用带引号的字符串(’ab’)、十六进制字符串(X’6162’,0x6162)或位值(b’nnnn’);formatID是无符号整数;为了安全起见,将gtrid和bqual写为十六进制字符串

示例
  Xid xid1 = new MyXid(100, new byte[] {0x01}, new byte[] {0x02});
  Xid xid2 = new MyXid(100, new byte[] {0x11}, new byte[] {0x12});

###展示的data为xid,但显示格式有问题,应为十六进制显示
mysql> XA RECOVER;
+----------+--------------+--------------+------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+------+
|      100 |            1 |            1 |    |
+----------+--------------+--------------+------+
1 row in set (0.00 sec)

mysql> XA RECOVER CONVERT XID;
+----------+--------------+--------------+--------+
| formatID | gtrid_length | bqual_length | data   |
+----------+--------------+--------------+--------+
|      100 |            1 |            1 | 0x1112 |
+----------+--------------+--------------+--------+
1 row in set (0.00 sec)

###进行回滚
mysql> xa rollback 0x11,0x12,100;
Query OK, 0 rows affected (0.01 sec)

###再次查看
mysql> XA RECOVER CONVERT XID;
Empty set (0.00 sec)

xid值通常由事务管理器生成。一个TM生成的值必须不同于其他TM生成的值。给定的TM必须能够在XA RECOVER语句返回的值列表中识别自己的xid值

一个或多个XA事务可以是同一全局事务的一部分。给定全局事务中的所有XA事务都必须在xid值中使用相同的gtrid值。因此,gtrid值必须是全局唯一的,这样给定的XA事务所属的全局事务就不会有任何歧义。对于全局事务中的每个XA事务,xid值的bqual部分必须不同(要求bqual值不同是当前MySQL XA实现的一个限制。它不是XA规范的一部分。)

官方示例

仅包含RM示例部分

mysql> XA RECOVER;
+----------+--------------+--------------+--------+
| formatID | gtrid_length | bqual_length | data   |
+----------+--------------+--------------+--------+
|        7 |            3 |            3 | abcdef |
+----------+--------------+--------------+--------+


The output columns have the following meanings:
    formatID is the formatID part of the transaction xid
    gtrid_length is the length in bytes of the gtrid part of the xid
    bqual_length is the length in bytes of the bqual part of the xid
    data is the concatenation of the gtrid and bqual parts of the xid

XA事务的状态

https://dev.mysql.com/doc/refman/8.0/en/xa-states.html

状态参考https://dev.mysql.com/doc/refman/8.0/en/xa-states.html

如果XA事务处于活动状态,则不能发出任何导致隐式提交的语句(完整隐式提交语句)。这将违反XA契约,因为您无法回滚XA事务

xa与本地事务

给定客户端连接的上下文中,XA事务和本地(非XA)事务是互斥的。例如,如果发出XA START以开始XA事务,则在提交或回滚XA事务之前,无法启动本地事务。相反,如果使用START transaction启动了本地事务,则在提交或回滚事务之前,不能使用XA语句。

锁超时示例

account表并未建立任何索引。带范围的sql语句会锁住整张表,影响其他会话的执行……与XA和本地事务互斥没有关系。

image.png

官方示例

mysql> XA START 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> update account set money = 1000+10 where name = 'bb';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> XA END 'xatest';
Query OK, 0 rows affected (0.00 sec)

mysql> XA RECOVER;
Empty set (0.00 sec)

mysql> XA PREPARE 'xatest';
Query OK, 0 rows affected (0.01 sec)

mysql> XA RECOVER;
+----------+--------------+--------------+--------+
| formatID | gtrid_length | bqual_length | data   |
+----------+--------------+--------------+--------+
|        1 |            6 |            0 | xatest |
+----------+--------------+--------------+--------+
1 row in set (0.00 sec)

mysql> xa rollback 'xatest';
Query OK, 0 rows affected (0.01 sec)

示例二完整的XID

mysql> XA START 'globalID','bID',100;
Query OK, 0 rows affected (0.00 sec)

mysql>
mysql> insert into account select 100,'cc';
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> select * from account;
+-------+------+
| money | name |
+-------+------+
|  1000 | bb   |
|   200 | dd   |
|   100 | cc   |
+-------+------+
3 rows in set (0.00 sec)

mysql> xa end 'globalID','bID',100;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
mysql>
mysql> xa prepare 'globalID','bID',100;
Query OK, 0 rows affected (0.01 sec)

mysql> xa recover;
+----------+--------------+--------------+-------------+
| formatID | gtrid_length | bqual_length | data        |
+----------+--------------+--------------+-------------+
|      100 |            8 |            3 | globalIDbID |
+----------+--------------+--------------+-------------+
1 row in set (0.00 sec)

mysql> xa commit  'globalID','bID',100;
Query OK, 0 rows affected (0.01 sec)