不能靠xa rollback或xa commit重试解决——若报error 1397 (xae04): xaer_nota,说明mysql已丢失xid元数据,仅剩日志残留;需先查information_schema.innodb_trx确认是否真在内存中存活,再结合formatid、gtrid_length、bqual_length还原完整xid,并验证外部系统状态后谨慎清理。

不能靠XA ROLLBACK或XA COMMIT重试解决——如果命令返回ERROR 1397 (XAE04): XAER_NOTA,说明MySQL已丢失该XID的元数据,事务状态在InnoDB内存和undo中都不存在,只剩日志残留。
先确认是不是真“悬挂”,别信XA RECOVER alone
XA RECOVER只读取binlog/XA log残留,不是实时状态。真正能反映当前事务锁持有情况的是内存态:
- 执行
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_state = 'PREPARED':如果有结果,说明事务还在内存中“活着”,可尝试XA ROLLBACK或XA COMMIT - 查
performance_schema.data_locks:看是否有lock_data对应你怀疑的XID;没有锁占用,基本就是幽灵记录 - 运行
SHOW ENGINE INNODB STATUS,在TRANSACTIONS和LOGsection里找PREPARE崩溃线索,比如*** ERROR: ... during recovery
拼出完整XID再操作,data字段不能直接复制
XA RECOVER输出的data是base64编码的二进制内容,且不带前导零;单独复制它会丢格式、错业务标识。必须结合formatID、gtrid_length、bqual_length三者还原:
- 用
CONV(SUBSTR(data, 1, 2), 16, 10)之类方式解码前缀,或更稳妥地用Python base64.b64decode + hexlify校验 - 常见业务XID格式如
service:order:20260612001,若data解码后是736572766963653a6f726465723a3230323630363132303031,需转为ASCII确认 - 误操作风险极高:对已在其他节点提交的XID执行
XA ROLLBACK,等于人为制造数据丢失
清理前必须验证外部系统状态
XA事务若参与JTA/MQ/Seata等外部协调器,MySQL端单方面清理会导致跨系统不一致:
- 查MQ消费位点、Kafka offset或Seata
undo_log表,确认该XID是否已在下游完成提交或回滚 - 检查应用层事务日志(如Spring Boot的
@Transactionaltrace ID),比对时间戳与XA RECOVER中gtrid是否匹配 - 若涉及Cetus中间件,必须调用其
xa-suspension-tool工具,它会自动比对binlog与各分片库状态,而非直接连MySQL执行XA ROLLBACK
生产环境慎用innodb_force_recovery,8.0后基本不可行
MySQL 5.7可通过设innodb_force_recovery = 1跳过prepare校验后执行XA ROLLBACK;但8.0+对此限制极严,多数场景下该参数无效:
- 强制恢复模式下无法写入任何数据,
XA ROLLBACK会被拒绝 - 真实可行路径只有两条:dump全库reload(停机窗口大),或人工从binlog解析出该XID对应的DML并反向补偿(需业务语义支持)
- 极端情况下删
ib_logfile*能清掉残留,但必须停库+备份redo,且仅适用于无主从同步的单节点测试环境
最易被忽略的点:MySQL 8.0.29+默认binlog_transaction_dependency_tracking = WRITESET,但它会让XA分支的binlog顺序错乱,导致从库上XA COMMIT失败——此时XA RECOVER看到的“悬挂”其实是主从状态分裂,不是本机事务卡住。











