MySQL XA分布式事务

DTP分布式事务处理模型

DTP(Distributed transaction processing,分布式事务处理),X/open 组织定义的一套分布式事务标准,用来规范全局事务处理.

参考:https://en.wikipedia.org/wiki/Distributed_transaction

DTP模型规范:

DTP

  • 应用程序(Application Program,简称AP):用于定义事务边界,并且在事务边界内对资源进行操作.
  • 资源管理器(Resource Manager,简称RM,也称事务的参与者):如数据库,文件系统等,并提供资源访问的方式.
  • 事务管理器(Transaction Manager,简称TM,也称事务协调者):负责分配事务唯一标识,监控事务的执行进度,并负责事务提交,回滚.

XA规范

文档: https://pubs.opengroup.org/onlinepubs/009680699/toc.pdf

MySQL XA

XA事务状态流转图:

事务状态流转图

一阶段提交: XA_IDLE-->commit one phase/rollback

二阶段提交: XA_IDLE-->XA_PARPARE-->commit/rollback

状态变化:

  1. xa start 启动事务,XA事务处于ACTIVE状态,可以执行事务SQL,注意处理active状态期间不能包含隐式提交;
  2. xa end XA事务进入 IDLE状态,可以发xa preparexa commit one phase;

    • xa prepare XA事务处于 PREPARED 状态,xa recover列出处于该状态的所有XA事务;
    • xa commit one phase 提交事务,终止事务;
  3. PREPARED状态可以发起,xa commit提交并终止事务 或 xa rollback回滚并终止事务;

XA命令

名称解释
xa_start负责开启或恢复一个事务分支,并且管理xid到调用线程
xa_end负责取消当前线程与事务分支的关联
xa_prepare负责询问RM,是否准备好了提交事务分支
xa_commit负责通知RM提交事务分支
xa_rollback负责通知RM回滚事务分支
xa_recover负责列出需要恢复的XA事务分支

核心命令:

-- 1.开始
XA {START|BEGIN} xid [JOIN|RESUME]
-- 2. 执行一些业务SQL
-- 3. 结束SQL
XA END xid [SUSPEND [FOR MIGRATE]]
-- 4. 预提交
XA PREPARE xid
-- 5.1. 提交
XA COMMIT xid [ONE PHASE]
-- 5.2  回滚
XA ROLLBACK xid
-- 6. 查看PREPARE列表
XA RECOVER [CONVERT XID]

xid 唯一事务ID, 最大64 个字节.由事务管理器生成,只要确保在事务期间不会冲突就可以.

XA START

开启一个xa事务或者恢复一个事务.

语法:

XA {START|BEGIN} xid [JOIN|RESUME];
  • 开启xid为'abc'的事务.
mysql> xa start 'abc';
Query OK, 0 rows affected (0.00 sec)

mysql> xa begin 'abc';
Query OK, 0 rows affected (0.00 sec)
  • 不支持事务嵌套,包括普通事务和xa事务,不能处于事务上下文中.
mysql> xa start '123';
Query OK, 0 rows affected (0.00 sec)

mysql> begin;
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  ACTIVE state
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> xa start '123';
ERROR 1400 (XAE09): XAER_OUTSIDE: Some work is done outside global transaction
  • xid重复
mysql> xa start 'abc';
ERROR 1440 (XAE08): XAER_DUPID: The XID already exists
  • 恢复

状态为IDLE(空闲)时可以通过xa start 'abc' resume恢复为ACTIVE状态.

mysql> xa start 'abc';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1.t2(ID) values(200);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test1.t2;
+------+
| ID   |
+------+
|  100 |
|  200 |
+------+
2 rows in set (0.00 sec)

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

mysql> select * from test1.t2;
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
mysql> xa start 'abc' resume;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1.t2;
+------+
| ID   |
+------+
|  100 |
|  200 |
+------+
2 rows in set (0.00 sec)

不为IDLE状态时,报错.

mysql> xa start 'abc' resume;
ERROR 1398 (XAE05): XAER_INVAL: Invalid arguments (or unsupported command)

XA END

结束一个XA事务.

语法:

XA END xid [SUSPEND [FOR MIGRATE]] 
mysql> xa start 'abc' ;
Query OK, 0 rows affected (0.00 sec)

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

状态不是ACTIVE状态时报错.

mysql> xa end 'abc';
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  NON-EXISTING state

已经end转成IDLE状态

mysql> xa end 'abc';
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state

已经预提交

mysql> xa end 'abc';
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  PREPARED state

不存在的XID

mysql> xa end '123';
ERROR 1397 (XAE04): XAER_NOTA: Unknown XID

不支持[SUSPEND [FOR MIGRATE] 语句

mysql> xa end 'abc' SUSPEND;
ERROR 1398 (XAE05): XAER_INVAL: Invalid arguments (or unsupported command)

XA Commit ONE PHASE

一阶段直接提交.

语法:

XA COMMIT xid ONE PHASE; 
mysql> xa start 'abc';
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1.t2;
+------+
| ID   |
+------+
|  100 |
|  200 |
+------+
2 rows in set (0.00 sec)

mysql> insert into test1.t2(ID) values(300);
Query OK, 1 row affected (0.01 sec)

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

mysql> xa commit 'abc';
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state
mysql> xa commit 'abc' one phase;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1.t2;
+------+
| ID   |
+------+
|  100 |
|  200 |
|  300 |
+------+
3 rows in set (0.00 sec)

XA ROLLBACK

回滚并终止事务.

处于'IDLE','PREPARED'状态可以回滚.

语法:

XA ROLLBACK xid;
mysql> xa start 'abc';
Query OK, 0 rows affected (0.00 sec)

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

mysql> xa rollback 'abc';
Query OK, 0 rows affected (0.00 sec)

未知XID

mysql> xa rollback 'abc';
ERROR 1397 (XAE04): XAER_NOTA: Unknown XID

Active状态

mysql> xa rollback 'abc';
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  ACTIVE state

XA PREPARE

预提交,准备提交.会被XA RECOVER 列出来,断开连接恢复后可以rollback和commit.

语法:

XA PREPARE xid;
mysql> xa recover;
Empty set (0.00 sec)

mysql> xa start 'abc';
Query OK, 0 rows affected (0.00 sec)

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

mysql> xa recover;
Empty set (0.00 sec)

mysql> xa prepare 'abc';
Query OK, 0 rows affected (0.00 sec)

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

此时即使进程断开或服务重启,也可以操作xid.

image-20240111191749135

锁定表,如果不commit或rollback,表一直被锁定状态.

image-20240111193249887

XA COMMIT

二阶段提交和XA Commit ONE PHASE 结果一样.

需要在PREPARE状态下.

语法:

XA COMMIT xid;
mysql> xa start 'abc';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1.t2(ID) values(600);
Query OK, 1 row affected (0.00 sec)

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

mysql> xa prepare 'abc';
Query OK, 0 rows affected (0.00 sec)

mysql> xa commit 'abc';
Query OK, 0 rows affected (0.00 sec)

Active状态下报错

mysql> xa commit 'abc';
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  ACTIVE state

未知XID

mysql> xa commit 'abc';
ERROR 1397 (XAE04): XAER_NOTA: Unknown XID

IDLE状态报错

mysql> xa commit 'abc';
ERROR 1399 (XAE07): XAER_RMFAIL: The command cannot be executed when global transaction is in the  IDLE state

可以跨进程commit

image-20240112132749258

XA RECOVER

列出可恢复的xa事务,只有PREPARED状态.

语法:

XA RECOVER;
mysql> xa end 'test1';
Query OK, 0 rows affected (0.00 sec)

mysql> xa recover;
Empty set (0.00 sec)

mysql> xa prepare 'test1';
Query OK, 0 rows affected (0.00 sec)

mysql> xa recover;
+----------+--------------+--------------+-------+
| formatID | gtrid_length | bqual_length | data  |
+----------+--------------+--------------+-------+
|        1 |            5 |            0 | test1 |
+----------+--------------+--------------+-------+
1 row in set (0.00 sec)

连接断开可以恢复.

image-20240112135206418

mysql> xa rollback 'test1';
Query OK, 0 rows affected (0.00 sec)

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

如果XID乱码,可以转16进制.

XA RECOVER CONVERT XID;
mysql>
mysql> xa start '\r123';
Query OK, 0 rows affected (0.01 sec)

mysql> xa end '\r123';
Query OK, 0 rows affected (0.00 sec)

mysql> xa prepare '\r123';
Query OK, 0 rows affected (0.01 sec)

mysql> xa recover;
+----------+--------------+--------------+------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+------+
123 |    1 |            4 |            0 |
+----------+--------------+--------------+------+
1 row in set (0.01 sec)

mysql> xa recover convert xid;
+----------+--------------+--------------+------------+
| formatID | gtrid_length | bqual_length | data       |
+----------+--------------+--------------+------------+
|        1 |            4 |            0 | 0x0D313233 |
+----------+--------------+--------------+------------+
1 row in set (0.00 sec)

mysql> xa rollback 0x0D313233;
Query OK, 0 rows affected (0.00 sec)

Mysql5.7之前差异

mysql从5.0版本开始,innoDB存储支持XA协议. 5.7.7版本之后得到完善.

差异:

  • 5.5.7之前客户端连接终止或服务器正常退出,则PREPARED事务将回滚.

之后的版本由用户选择commit或rollback;

5.5版本:

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.5.62    |
+-----------+
1 row in set (0.00 sec)

mysql> xa start 'test';
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test.t1;
Empty set (0.00 sec)

mysql> insert into test.t1(id) values(100);
Query OK, 1 row affected (0.01 sec)

mysql> xa end 'test';
Query OK, 0 rows affected (0.01 sec)

mysql> xa prepare 'test';
Query OK, 0 rows affected (0.01 sec)

mysql> select * from test.t1;
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Connection id:    7
Current database: test

Empty set (0.02 sec)

mysql> xa recover;
Empty set (0.01 sec)

mysql> xa commit 'test';
ERROR 1397 (XAE04): XAER_NOTA: Unknown XID

8.0版:

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.2.0     |
+-----------+
1 row in set (0.00 sec)

mysql> xa start 'test';
Query OK, 0 rows affected (0.01 sec)

mysql> select * from test.t1;
Empty set (0.00 sec)

mysql> insert into test.t1(id) values(100);
Query OK, 1 row affected (0.00 sec)

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

mysql> xa prepare 'test';
Query OK, 0 rows affected (0.01 sec)

mysql> kill 14;
ERROR 1317 (70100): Query execution was interrupted
mysql> select * from test.t1;
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Connection id:    16
Current database: *** NONE ***

Empty set (0.03 sec)

mysql> xa recover;
+----------+--------------+--------------+------+
| formatID | gtrid_length | bqual_length | data |
+----------+--------------+--------------+------+
|        1 |            4 |            0 | test |
+----------+--------------+--------------+------+
1 row in set (0.00 sec)

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

mysql> select * from test.t1;
+------+
| id   |
+------+
|  100 |
+------+
1 row in set (0.01 sec)
  • prepare后异常后可以恢复到prepare状态.

可以继续xa commit和xa rollback

5.5:

mysql> show processlist;
+----+------+------------------+------+---------+------+-------+------------------+
| Id | User | Host             | db   | Command | Time | State | Info             |
+----+------+------------------+------+---------+------+-------+------------------+
|  8 | root | 172.18.0.1:62930 | test | Query   |    0 | NULL  | show processlist |
+----+------+------------------+------+---------+------+-------+------------------+
1 row in set (0.01 sec)

mysql> xa start 'test';
Query OK, 0 rows affected (0.00 sec)

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

mysql> xa prepare 'test';
Query OK, 0 rows affected (0.00 sec)

mysql> kill 8;
ERROR 1317 (70100): Query execution was interrupted
mysql> xa commit 'test';
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Connection id:    9
Current database: test

ERROR 1397 (XAE04): XAER_NOTA: Unknown XID

8.0

mysql> show processlist;
+----+-----------------+------------------+------+---------+------+------------------------+------------------+
| Id | User            | Host             | db   | Command | Time | State                  | Info             |
+----+-----------------+------------------+------+---------+------+------------------------+------------------+
|  5 | event_scheduler | localhost        | NULL | Daemon  | 9081 | Waiting on empty queue | NULL             |
| 17 | root            | 172.18.0.1:63594 | NULL | Query   |    0 | init                   | show processlist |
+----+-----------------+------------------+------+---------+------+------------------------+------------------+
2 rows in set, 1 warning (0.00 sec)

mysql> xa start 'test';
Query OK, 0 rows affected (0.00 sec)

mysql> xa end 'test';
Query OK, 0 rows affected (0.01 sec)

mysql> xa prepare 'test';
Query OK, 0 rows affected (0.01 sec)

mysql> kill 17;
ERROR 1317 (70100): Query execution was interrupted
mysql> xa commit 'test';
ERROR 2013 (HY000): Lost connection to MySQL server during query
No connection. Trying to reconnect...
Connection id:    18
Current database: *** NONE ***

Query OK, 0 rows affected (0.04 sec)
  • prepare后日志持久化

5.5 没生成binlog日志

mysql> xa start 'test';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test.t1(id) values(100);
Query OK, 1 row affected (0.01 sec)

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

mysql> xa prepare 'test';
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW BINLOG events;
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
| Log_name         | Pos | Event_type  | Server_id | End_log_pos | Info                                  |
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
| mysql-bin.000001 |   4 | Format_desc |         1 |         107 | Server ver: 5.5.62-log, Binlog ver: 4 |
| mysql-bin.000001 | 107 | Query       |         1 |         194 | create table test.t1(id INT)          |
+------------------+-----+-------------+-----------+-------------+---------------------------------------+
2 rows in set (0.00 sec)

8.0 持久化日志,多了XA_prepare类型

mysql> xa start 'test';
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test.t1(id) values(100);
Query OK, 1 row affected (0.00 sec)

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

mysql>  xa prepare 'test';
Query OK, 0 rows affected (0.01 sec)

mysql> SHOW BINLOG events;
+---------------+-----+----------------+-----------+-------------+--------------------------------------+
| Log_name      | Pos | Event_type     | Server_id | End_log_pos | Info                                 |
+---------------+-----+----------------+-----------+-------------+--------------------------------------+
| binlog.000001 |   4 | Format_desc    |         1 |         126 | Server ver: 8.2.0, Binlog ver: 4     |
| binlog.000001 | 126 | Previous_gtids |         1 |         157 |                                      |
| binlog.000001 | 157 | Anonymous_Gtid |         1 |         236 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| binlog.000001 | 236 | Query          |         1 |         328 | XA START X'74657374',X'',1           |
| binlog.000001 | 328 | Table_map      |         1 |         376 | table_id: 108 (test.t1)              |
| binlog.000001 | 376 | Write_rows     |         1 |         416 | table_id: 108 flags: STMT_END_F      |
| binlog.000001 | 416 | Query          |         1 |         506 | XA END X'74657374',X'',1             |
| binlog.000001 | 506 | XA_prepare     |         1 |         546 | XA PREPARE X'74657374',X'',1         |
+---------------+-----+----------------+-----------+-------------+--------------------------------------+
8 rows in set (0.00 sec)
  • MySQL 8.0.29 开始支持分离事务

    xa_detach_on_prepare为ON时可以分离事务,事备进入prepared状态后不用等rollback或commit,就可以开启另一个事务.或在另一个进程rollback或commit;

嵌套XA事务:

# xa1 开始
mysql> xa start 'xa1';
Query OK, 0 rows affected (0.01 sec)

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

mysql> xa prepare 'xa1';
Query OK, 0 rows affected (0.01 sec)
# xa2事务开启
mysql> xa start 'xa2';
Query OK, 0 rows affected (0.00 sec)

mysql> xa end 'xa2';
Query OK, 0 rows affected (0.00 sec)
# xa2结束
mysql> xa rollback 'xa2';
Query OK, 0 rows affected (0.01 sec)
# xa1 结束
mysql> xa commit 'xa1';
Query OK, 0 rows affected (0.00 sec)

XA事务嵌套普通事务

mysql> xa start 'xa1';
Query OK, 0 rows affected (0.01 sec)

mysql> xa end 'xa1';
Query OK, 0 rows affected (0.01 sec)

mysql> xa prepare 'xa1';
Query OK, 0 rows affected (0.01 sec)

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> xa rollback 'xa1';
Query OK, 0 rows affected (0.00 sec)

XA PHP示例代码

单实例一阶段提交:

和普通事务一样.

$host1 = "127.0.0.1:13306";

$username = "root";
$password = "123456";
$dsn1="mysql:host=$host1;";
$rm1Conn = new PDO($dsn1, $username, $password);

// TM统计管理XID
$xaId=uniqid("");

try {
    // XA 开始
    $rm1Conn->exec("XA START '$xaId'");
    $sql1 = "INSERT INTO test1.t1 values (100)";
    $rm1Conn->exec($sql1);
    $sql2 = "INSERT INTO test2.t1 values (200)";
    $rm1Conn->exec($sql2);
    // XA 结束
    $rm1Conn->exec("XA END '$xaId'");

    // 提交
    $commitRet1=$rm1Conn->exec("XA COMMIT '$xaId' ONE PHASE");
    
    if($commitRet1===false){
        echo 'fail'.PHP_EOL;
    }else{
        echo 'ok'.PHP_EOL;
    }
}catch (Exception $e){
    echo $e->getMessage();
    // 回滚
    $rm1Conn->exec("XA ROLLBACK '$xaId'");
}

多实例2阶段提交:

$host1 = "127.0.0.1:13306";
$host2 = "127.0.0.1:23306";

$username = "root";
$password = "123456";
$dsn1="mysql:host=$host1;dbname=test";
$dsn2="mysql:host=$host2;dbname=test";
$rm1Conn = new PDO($dsn1, $username, $password);
$rm2Conn = new PDO($dsn2, $username, $password);
$xaId=uniqid("");
try {
    // XA 开始
    $rm1Conn->exec("XA START '$xaId'");
    $sql1 = "INSERT INTO t1 values (201)";
    $rm1Conn->exec($sql1);
    $rm1Conn->exec("XA END '$xaId'");

    $rm2Conn->exec("XA START '$xaId'");
    $sql2 = "INSERT INTO t1 values (202)";
    $rm2Conn->exec($sql2);
    $rm2Conn->exec("XA END '$xaId'");
    // XA 结束
    // 1阶段提交
    $commitRet1=$rm1Conn->exec("XA COMMIT '$xaId' ONE PHASE");
    $commitRet2=$rm2Conn->exec("XA COMMIT '$xaId' ONE PHASE");
    echo 'success';
}catch (Exception $e){
   $rm1Conn->exec("XA ROLLBACK '$xaId'");
   $rm2Conn->exec("XA ROLLBACK '$xaId'");
}

多实例2阶段提交:

<?php
declare(strict_types=1);

$host1 = "127.0.0.1:13306";
$host2 = "127.0.0.1:23306";

$username = "root";
$password = "123456";
$dsn1="mysql:host=$host1;dbname=test";
$dsn2="mysql:host=$host2;dbname=test";
$rm1Conn = new PDO($dsn1, $username, $password);
$rm2Conn = new PDO($dsn2, $username, $password);

// TM统计管理XID
$xaId=uniqid("");
try {
    // XA 开始
    $rm1Conn->exec("XA START '$xaId'");
    $sql1 = "INSERT INTO t1 values (201)";
    $rm1Conn->exec($sql1);
    $rm1Conn->exec("XA END '$xaId'");
        
    $rm2Conn->exec("XA START '$xaId'");
    $sql2 = "INSERT INTO t1 values (202)";
    $rm2Conn->exec($sql2);
    $rm2Conn->exec("XA END '$xaId'");
    // XA 结束

    // 1阶段预提交
    $preRet1=$rm1Conn->exec("XA PREPARE '$xaId'");
    $preRet2=$rm2Conn->exec("XA PREPARE '$xaId'");
    if($preRet1===false || $preRet2===false){
        echo 'fail'.PHP_EOL;
        throw new Exception('prepare error.');
    }

    // 2阶段提交
    $commitRet1=$rm1Conn->exec("XA COMMIT '$xaId'");
    $commitRet2=$rm2Conn->exec("XA COMMIT '$xaId'");
    if($commitRet1===false || $commitRet2===false){
        echo 'fail'.PHP_EOL;
    }else{
        echo 'ok'.PHP_EOL;
    }
}catch (Exception $e){
    echo $e->getMessage();
    // 回滚
    $rm1Conn->exec("XA ROLLBACK '$xaId'");
    $rm2Conn->exec("XA ROLLBACK '$xaId'");
}

XA事务异常处理

不同阶段时的异常处理.

  1. Active,IDLE 异常时不影响数据一致性;处理方案:重试或不处理;
  2. Rollback 不一致时;处理方案:补偿rollback;
  3. Prepare 状态;处理方案:重试或补偿rollback;
  4. 一阶段 ONE PHASE Commit状态;失败重试,无法补偿commit.可以补偿SQL;
  5. 二阶段Commit状态;重试,补偿commit或补偿SQL;

业务处理

  1. prepare失败为业务失败,统一补偿失败处理即回滚.
  2. 一阶段commit不作考虑.
  3. 二除段commit失败,不允许失败,继续重试commit最后进入人工处理.prepare成功后一般由于网络造成的失败.

补偿业务:

  1. 收集prepare阶段之后的xID.
  2. 延迟清空prepare失败的xID.
  3. 重试commit阶段的xID.
  4. 重试失败后进入预警,进入人工处理.

原作者:阿金
本文地址:https://hi-arkin.com/archives/mysql-xa.html

标签: mysql xa DTP分布式事务

(本篇完)

评论