未提交事务在主从切换瞬间直接丢失,MySQL不回滚、不记录、不补偿;因kill-9强杀导致InnoDB来不及清理,UNDO_LOG、Buffer Pool、redo log中未commit数据全部丢弃,仅已commit且ACK的binlog被从库同步,应用层须通过幂等设计、状态表或异步消息自行兜底。

未提交事务在切换瞬间直接蒸发,MySQL不做回滚、不记日志、不补偿
kill -9 强杀导致 InnoDB 来不及清理
主库被强制终止(如 kill -9)时,InnoDB 进程立即退出,所有内存结构清空:UNDO_LOG 中的回滚段、Buffer Pool 中的脏页、redo log 中已写但未 commit 的记录全部丢失。此时 INFORMATION_SCHEMA.INNODB_TRX 表为空,SHOW ENGINE INNODB STATUS 无法还原任何上下文,事务 ID 甚至不会出现在 gtid_executed 集合里。
常见误操作包括:用 kill -9 处理卡住的连接、运维脚本未加判断直接强杀 mysqld、容器被 OOMKilled。这些场景下,事务不是“没提交”,而是“根本没机会进入提交流程”。
autocommit=0 下连接异常断开才触发自动回滚
MySQL 只在特定条件下对未提交事务执行服务端自动回滚:
- 客户端崩溃、网络中断、
wait_timeout超时等「连接异常终止」场景,且autocommit=0 -
KILL CONNECTION <thread_id></thread_id>命令也会触发回滚 - 但
KILL QUERY <thread_id></thread_id>不终止连接,事务仍保持打开状态 -
autocommit=1模式下,每条语句是独立事务,断开前已隐式提交,看似“没丢”,实则不是同一事务语义
问题在于:主从切换常伴随 VIP 漂移、Keepalived 主动 kill 进程、或 DBA 手动 systemctl stop mysqld —— 这些都不是“连接异常断开”,而是进程级终止,自动回滚机制完全不生效。
binlog 和 redo log 不一致导致从库多出/少数据
即使事务已 commit,也可能因日志刷盘策略不同步而丢失:
-
sync_binlog=0:binlog 只写入 page cache,未 fsync 到磁盘;主库宕机后这部分 binlog 丢失,但从库 IO 线程可能已读走并重放 -
innodb_flush_log_at_trx_commit=0或=2:redo log 未落盘,崩溃后已 commit 事务无法通过 crash recovery 恢复 - XA 协调失败:
innodb_support_xa=0(MySQL 5.7.7+ 默认关闭)时,binlog 与 redo log 提交顺序可能错乱,造成主库回滚但从库执行
这类问题在切换后表现为:新主库上查不到某条刚插入的数据,或者出现唯一键冲突——不是事务丢了,而是主库和从库对“是否已提交”的判定不一致。
应用层看不到事务生命周期,补偿必须前置设计
最容易被忽略的是:事务状态无法跨主库延续,锁、临时表、会话变量、游标全失效。一旦切换发生,以下模式必然出问题:
-
SELECT FOR UPDATE+ 外部 HTTP 回调:锁在老主库释放,回调结果写入新主库,中间态无法对齐 - 本地事务中发 MQ 消息但未等 ACK:消息可能重复投递,新主库上执行两次
- 依赖
LAST_INSERT_ID()或会话级变量做后续逻辑:切换后变量重置,业务链路断裂
真正可靠的兜底不是等 MySQL 补偿,而是在事务外先落可查询的状态(如 payment_pending 记录),再用异步任务轮询终态。补偿逻辑必须覆盖 Lost connection 错误,且不能假设“老主库还能连上”。


















