这是与 XA 事务相关的令人兴奋的故障排除之一,让我们深入探讨。首先我为大家提供一些背景知识。
对于我们的一个客户,当我们尝试删除一个表时,它正在等待元数据锁定。在调试时,其中一个 XA 事务持有共享写锁并导致所有其他本地事务上的元数据锁。
让我们从 Performance Schema 中查看元数据锁。
mysql> select OBJECT_TYPE,OBJECT_SCHEMA,OBJECT_NAME, LOCK_TYPE,LOCK_STATUS,SOURCE from performance_schema.metadata_locks\G
******************* 1. row *********************
OBJECT_TYPE: TABLE
OBJECT_SCHEMA: sbtest
OBJECT_NAME: sbtest_table1
LOCK_TYPE: SHARED_WRITE
LOCK_STATUS: GRANTED
SOURCE: xa.cc:284
******************* 2. row *********************
OBJECT_TYPE: TABLE
OBJECT_SCHEMA: sbtest
OBJECT_NAME: sbtest_table2
LOCK_TYPE: SHARED_WRITE
LOCK_STATUS: GRANTED
SOURCE: xa.cc:284
******************* 3. row *********************
OBJECT_TYPE: TABLE
OBJECT_SCHEMA: sbtest
OBJECT_NAME: sbtest_table3
LOCK_TYPE: SHARED_WRITE
LOCK_STATUS: GRANTED
SOURCE: xa.cc:284
******************* 4. row *********************
OBJECT_TYPE: TABLE
OBJECT_SCHEMA: sbtest
OBJECT_NAME: sbtest_table1
LOCK_TYPE: EXCLUSIVE
LOCK_STATUS: PENDING
SOURCE: xa.cc:284
到底发生了什么?
在 MySQL 8.0.28 及更早版本中,XA 事务和本地(非 XA)事务是互斥的。 (8.0.29 中的 XA 更改)例如,如果已发出 XA START 以开始 XA 事务,则在提交或回滚 XA 事务之前无法启动本地事务。在我们的例子中,XA 事务已经处于 PREPARED 状态(既没有提交也没有回滚),持有锁。因此,我们试图启动的本地事务无法获取锁,因为它们是互斥的。
当事务未提交 (XA COMMIT;) 或未回滚 (XA ROLLBACK) 时,XA 事务将进入 PREPARED 状态;
XA 交易流程

我们可以从Show Engine InnoDB 状态输出中看到,事务已达到 Prepared 状态,\。
---TRANSACTION 28992918, ACTIVE (PREPARED) 1072517 sec recovered trx5 lock struct(s), heap size 1128, 0 row lock(s), undo log entries 8---TRANSACTION 234688, ACTIVE (PREPARED) 1072517 sec recovered trx3 lock struct(s), heap size 1128, 0 row lock(s), undo log entries 6---TRANSACTION 25949, ACTIVE (PREPARED) 1072517 sec recovered trx1 lock struct(s), heap size 1128, 0 row lock(s), undo log entries 1
我们可以通过运行 XA RECOVER 来获取所有 XA Prepared 事务的列表;要提交或回滚这些 XA 事务,我们需要知道每个 XA 事务的 XID
mysql> XA 恢复;
+------------+--------------+--------------+-------- --------------------------------------------------+
| 格式ID | gtrid_length | bqual_length | 数据 |
+------------+--------------+--------------+-------- --------------------------------------------------+
| 1 | 38 | 1 | 3d36dccd-61d0-4ae1-9b39-f9ccc2400d44:44 |
| 1 | 39 | 2 | 11740f2a-8a85-4b33-b924-982c1539d197:2222 |
| 1 | 41 | 4 |0d0afb17-c480-4a30-88c0-907b20794d13:10011001 |
+------------+--------------+--------------+-------- --------------------------------------------------+
我们是如何解决这个问题的?
我们已经知道,每个 XA 事务都以 XA 关键字开头,后跟 XID。XID 是 XA 事务标识符。一个 XID 值包含一到三个部分:
- Gtrid 是一个全局事务标识符。
- Bqual是一个分支限定符。
- FormatID是一个数字,用于标识 gtrid 和 bqual 值使用的格式。
- 对于全局事务中的每个 XA 事务,XID 值的 bqual 部分必须不同。
mysql> xa 恢复转换 xid;
+------------+--------------+--------------+-------- ---------------------------------------------+
| 格式ID | gtrid_length | bqual_length | 数据 |
+------------+--------------+--------------+-------- ---------------------------------------------+
| 1 | 6 | 2 | 0x1A64306166623137 |
| 1 | 7 | 4 | 0x31313734306632612D3861 | +------------+--------------+--------------+-------- ---------------------------------------------+
3 行一组(0.00 秒)
上面的“ XA RECOVER CONVERT XID ”给出了十六进制值的XID值。gtrid_length 和 bqual_length 字段告诉我们开始和停止的位置。我们需要以字节为单位的 gtrid_length 和以字节为单位的 bqual_length 并分离出这些值。
让我们从上面的输出中获取数据列值。让我们根据 gtrid_length(给出为 6)和 bqual_length(显示为 2)值将值拆分为字节。
由于“1A”是单个字节,请记住这一点,我们需要拆分数据值。
0x 1A6430616662 3137
Gtrid_length - 6 == > (1A 64 30 61 66 62)
Bqual_length - 2 == > (31 37)
让我们现在尝试提交事务
mysql>XA COMMIT X’1A6430616662’,X’3137’,1;
Query OK, 0 rows affected (0.03 sec)
其中 1 是格式标识符
现在让我们进行第二次交易。基于给定的gtrid_length和bqual_length值,我们正在拆分数据值。
0x 31313734306632 612D3861
Gtrid_length - 7 == > (31 31 37 34 30 66 32)
Bqual_length - 4 == > (61 2D 38 61)
mysql>XA COMMIT X’31313734306632’,X’612D3861’,1
Query OK, 0 rows affected (0.03 sec)
在这里,“1”是格式标识符
关键信息
这样,从 XA RECOVER CONVERT XID 输出中,我们将能够获得任何处于准备状态的 XA 事务的 XID,并且我们可以根据我们的要求提交/回滚它。
为这次故障排除感到开心!
原文标题:Troubleshooting XA transactions in MySQL
原文作者:paulinjeyapriya
原文地址:https://mydbops.wordpress.com/2022/09/12/troubleshooting-xa-transaction-in-mysql/




