bigywater.tech
MySQL / InnoDB · 62

XA 两阶段事务

做一次真实的两阶段提交,故意在PREPARE之后关闭连接,看一个全新的、从未参与过这个事务的连接,能不能真实找到并完成它。

跨连接接力
PREPARE的事务真实被一个从未参与过的新连接接手完成
PREPARE≠COMMIT
真实验证了准备阶段的改动对外仍不可见

做的事:PREPARE之后,故意让原来的连接消失

连接①XA START 'xa_demo'; UPDATE accounts SET balance=balance-50 WHERE id=10; XA END 'xa_demo'; XA PREPARE 'xa_demo'; -- 这条mysql命令执行完就退出了,连接①真实不再存在

验证:连接①消失后,改动真实还没提交

实测 · 本机全新连接②的真实查询
SELECT id, balance FROM accounts WHERE id=10;
→ balance = 1000.00   ← 真实还是原值,PREPARE不等于COMMIT

XA PREPARE只是把这个事务的改动真实写进了redo log、准备好可以提交,但并没有真实提交——这时候连接①已经关闭,可这个"准备好但未提交"的事务真实没有被回滚,它变成了一个悬而未决、等待被处理的状态,独立于任何一个具体连接存在。

验证:全新连接真实能找到它、接手完成它

实测 · 本机再开一个全新连接③的真实操作
XA RECOVER;
→ formatID=1, gtrid_length=7, data='xa_demo'   ← 真实找到了这个悬而未决的事务

XA COMMIT 'xa_demo';
→ 真实提交成功

SELECT id, balance FROM accounts WHERE id=10;
→ balance = 950.00   ← 真实生效了
连接③从头到尾都没参与过这个事务最初的XA START,但它真实能通过XA RECOVER找到这个只凭一个字符串ID('xa_demo')标识的悬而未决事务,并且真实把它提交完成——这正是两阶段提交(2PC)设计的核心价值:一个分布式事务协调者(比如跨多个数据库、或者应用服务器本身)可以先让所有参与者都PREPARE,协调者自己记录"全部PREPARE成功"这个决定,之后哪怕某个连接断开、应用重启,只要协调者知道这个事务ID,就能真实用一个全新的连接找回并完成它——不会因为连接断开就永远悬在那里,也不会静默丢失。

分步演示:三个真实独立的连接,接力完成一次XA提交

每一步都是本文上面用真实独立的MySQL连接跑出来的原始结果。

连接可以消失,PREPARE之后的事务真实不会
这一步新验证的连接

    本文用到的工具

    • 本机 MySQL 26.7.0(InnoDB),accounts表,三个真实独立的连接接力完成一次XA事务
    • XA START/END/PREPARE/COMMIT + XA RECOVER
    京ICP备2026067502号-1京公网安备11010502063487号