应用跑批时偶尔报ERROR 1412: Table definition has changed, please retry transaction,重连后又恢复。要判断能否自动重试,先确认失败发生在哪个事务、同一时间有没有迁移任务重建相关表。

先给结论:旧快照可能读不到新表
1412的错误名是ER_TABLE_DEF_CHANGED。MySQL说明,部分ALTER TABLE会用新表替换旧表;旧事务再次对该表做一致性读时,原快照无法看到新表中的行,可能收到1412。同一个事务内重发失败SQL并不会替换原来的快照。
典型时间线是事务先通过另一张表的一致性读建立快照,另一会话随后重建目标表并完成DDL,原事务才开始访问该表。若原事务已访问目标表,DDL也可能先被元数据锁挡住,实际先后要看记录。
需要先查哪些信息
记录失败SQL、事务起止时间、数据库实例和SELECT VERSION(), @@session.transaction_isolation;的结果。按时间对照迁移日志中涉及目标表的ALTER TABLE,确认执行算法、开始与完成时刻,避免只盯当前表结构。
需要看仍在运行的InnoDB事务时,可在有权限的会话用SELECT trx_id, trx_started, trx_state, trx_mysql_thread_id FROM information_schema.innodb_trx ORDER BY trx_started;。该表是当前状态,历史需依赖应用或运维日志。
按整个业务单元回滚再试
对可安全重复的工作,显式ROLLBACK并用新事务重跑必要步骤。只读导出如果要求同一快照,按整批重新开始,避免混合两个时点的数据。涉及付款、消息发送等外部副作用时,先查业务流水和幂等键,再决定重试。数据库回滚不会撤销已发送的消息。
只对确认可重试的错误做有限次退避。若同类报错持续出现,先暂停冲突的迁移或批次,避免盲目重试压垮数据库。
能通过修改隔离级别解决吗
REPEATABLE READ的一致性读共享首次此类读建立的快照,READ COMMITTED则按一致性读重新取快照。后者改变同一事务内多次读取的语义。别为了1412直接修改全站默认隔离级别。先让重建型迁移与长事务错开,再按目标版本和表条件评估能否使用合适的DDL算法。
修复后看什么指标
可在萤光云或LightNode的隔离VPS用同版本MySQL复现迁移与长事务的时序。检查新事务返回结果完整、错误率回落、迁移窗口内不再有重叠的长任务。有写入的业务还应核对重复记录与外部操作次数。
FAQ
这是锁等待超时吗? 1412指表定义变化,与锁等待超时有不同的错误码和处理逻辑。
所有ALTER TABLE都会触发吗? 不会;取决于DDL实现、算法和事务时序。
必须重连吗? 对这个错误,关键是安全结束旧事务并建立新事务,未必需要新连接。
只重试最后一条SELECT可以吗? 若旧快照仍有效且没换事务,无法解决快照冲突。
能在正式库故意重建大表复现吗? 应先在预发测试,正式库只观察迁移和事务记录。
温馨提示
在迁移发布单写清DDL算法、超时上限、长事务窗口和失败后的恢复方式。只有读过副作用记录,才决定带写操作的事务能否重跑。


