XA事务卡在PREPARED状态不一定是网络抖动导致,根本原因是生命周期中断:XA START后未执行XA END即断连,MySQL不自动回滚,事务滞留XA RECOVER中呈PREPARED状态,锁不释放、DDL可能阻塞,且INFORMATION_SCHEMA.INNODB_TRX不可见。

XA事务卡在PREPARED状态,是不是网络抖动导致的?
不一定。网络抖动只是可能诱因之一,真正卡住的是事务生命周期中断——XA START后没走完XA END就断连,MySQL不会自动回滚,而是把事务钉在XA RECOVER里,状态为PREPARED。这时候锁不释放、DDL可能被阻塞、INFORMATION_SCHEMA.INNODB_TRX里还查不到它(因为不是普通事务),但XA RECOVER能列出来。
所以看到超时错误,别急着调超时参数,先确认是不是已有悬挂事务在占资源:
- 执行
XA RECOVER,看返回行数是否明显增多 - 对比
SHOW ENGINE INNODB STATUS里的LATEST FOREIGN KEY ERROR或LOG SECTION,有时能发现prepare阶段崩溃的痕迹 - 检查应用日志里有没有
ERROR 1397 (XAE04): XAER_RMFAIL或ERROR 1205 (HY000): Deadlock found——这类错误说明XA PREPARE根本没成功,事务压根没进2PC流程,XA RECOVER自然为空
max_prepared_transactions设多大才够用?
这个值不是“越大越好”,而是必须≥当前并发中处于PREPARED状态的最大事务数。默认是0(禁用XA),设太小会导致XA START直接报错ERROR 1400 (XAE09): XAER_OUTSIDE。
实操建议:
- 线上环境至少设为
100,金融/支付类系统建议256起 - 不要动态
SET GLOBAL修改,必须写进my.cnf并重启MySQL——该参数是只读的 - 改完后验证:
SELECT @@max_prepared_transactions;,再跑一次XA START+XA END+XA PREPARE链路,确认不报错
有没有真正的“XA超时”配置?
没有。MySQL本身不提供xa_transaction_timeout这类参数。所谓“超时”,其实是应用层或连接池控制的:比如JDBC的socketTimeout、Druid的maxWait、或者Spring的@Transactional(timeout = ...)。这些只管连接或方法级生命周期,对已进入PREPARED状态的XA事务完全无效。
换句话说:你调大了连接超时,只能防止建连失败;但一旦事务卡在PREPARED,它就会一直挂着,直到手动XA COMMIT或XA ROLLBACK,或者等MySQL实例重启(不推荐)。
所以关键动作是:
- 应用必须实现兜底扫描:定时跑
XA RECOVER,识别出超过5分钟未处理的data字段,主动发XA ROLLBACK - 所有
XA START调用必须包在try-finally里,确保无论成功失败都走到XA END - 避免在
XA START和XA END之间做耗时操作(如HTTP调用、文件IO)
为什么XA RECOVER出来的data字段看不懂?
因为它是二进制格式,不是Base64也不是JSON,MySQL官方不保证可读性,也不建议解析。它的唯一用途就是原样传给后续的XA COMMIT或XA ROLLBACK命令。
例如XA RECOVER返回:
formatID: 1, gtrid_length: 3, bqual_length: 0, data: 0x7861303031
你就得写成:
XA ROLLBACK X'7861303031';
而不是尝试UNHEX('7861303031')或转字符串——MySQL会拒绝执行。这点特别容易踩坑,尤其当脚本自动生成rollback语句时,data字段漏了X''包裹或用了错误的引号类型,就会报ERROR 1396 (XAE08): XAER_INVAL。


















