MySQL CREATE TABLE 后 ROLLBACK 没撤销:DDL 已提前提交
MySQL 普通 DDL 会隐式提交此前业务事务,后续 ROLLBACK 无法撤销。区分 InnoDB、atomic DDL 和临时表规则,将结构迁移移出业务事务并核对已提交数据。
应用已经开始 MySQL 事务,先修改业务数据,再执行 CREATE TABLE,后续异常进入 ROLLBACK,前面的修改和新表却仍存在。若使用的是普通表 DDL,应检查隐式提交:这类语句会在执行前结束当前事务,事后的回滚无法撤销已经提交的修改。
这在 InnoDB 中也成立。表支持事务,并不意味着所有涉及这张表的结构操作都能被同一笔用户事务回滚。以下按 MySQL 8.4 的规则说明普通 CREATE TABLE 等 DDL;临时表有不同边界,不能混用。
还原同一连接实际执行的顺序
检查业务事务内是否包含 CREATE TABLE、ALTER TABLE、DROP TABLE、CREATE INDEX 或 TRUNCATE TABLE 等语句,以及它们与数据写入的先后关系。框架调用 begin、commit、rollback 的位置,不能代替实际 SQL 顺序。
例如下面只是说明风险的 SQL 顺序,不能作为生产排查命令执行:
START TRANSACTION;
UPDATE accounts SET status = 'pending' WHERE id = 42;
CREATE TABLE maintenance_example (id INT PRIMARY KEY) ENGINE=InnoDB;
ROLLBACK;
普通 CREATE TABLE 执行前会提交当前事务,因此 UPDATE 不再属于最后这条 ROLLBACK 能撤销的范围。创建表本身也不会被用户的 ROLLBACK 撤销。示例数据和表名均为占位,验证只能在隔离数据中进行。
DDL 后可能还有新的数据事务,回滚能否撤销那些后续写入,要按会话自动提交模式和实际事务边界判断。不要看到最后调用 rollback 就把整个调用链都算作失败且未落库。
隐式提交发生在执行前,因此即使 DDL 后来失败,也不能仅凭这次结构操作报错就认定此前数据写入已回滚。需要逐项核对已提交的业务结果,而不是只检查新表是否存在。
InnoDB 与 atomic DDL 不能改变这条边界
autocommit 为 ON 时,显式 START TRANSACTION 仍会开始事务。把会话改为 autocommit=0,不会使普通 DDL 免于隐式提交;也不能通过反复 begin 在 MySQL 中创建任意嵌套事务。
MySQL 8.x 的 atomic DDL 让受支持的结构操作把数据字典、存储引擎操作与 binary log 变更作为一项原子操作处理,包含服务器中断时的恢复保障。它不是把 DDL 纳入应用的 START TRANSACTION ... ROLLBACK。
因此,升级到有 atomic DDL 的版本或把表改成 InnoDB,并不能让示例中的结构和业务数据一起回滚。也不要通过切换为不支持事务的存储引擎尝试解决,反而会失去原有数据事务保障。
临时表不提交,也不代表创建能回滚
CREATE TEMPORARY TABLE 与 DROP TEMPORARY TABLE 不会触发这里的隐式提交,但它们自身不能被 ROLLBACK 撤销。创建后再回滚,临时表仍可能存在。
对临时表执行 ALTER TABLE 或 CREATE INDEX 又会触发提交。不要把“TEMPORARY 创建不提交”扩展为所有临时表操作都可与业务事务自由混用。
临时表还改变了可见范围与生命周期,只能在业务确实需要会话临时数据时采用。将持久业务表临时化,不是保留原需求的替代方案。
将结构迁移移出业务写事务
普通应用表应由独立、受控的迁移流程建立或修改,业务事务使用已经准备好的结构。先保存当前结构、数据备份、迁移版本与恢复路径,再安排变更,避免在每次请求中创建或改表。
新旧应用同时运行时,迁移还要兼容两套代码,并评估 DDL 的锁、运行时间和资源影响。将 DDL 移到另一个连接,只能隔离它对原连接的事务边界影响,不能让结构操作与业务数据突然形成跨连接的原子事务。
如果需求本来就是“创建一个持久表并写入,任何失败都恢复到完全没发生”,需要重新设计流程。例如提前准备结构,把可回滚的数据修改放进明确的业务事务;或者用有记录、有身份和可重入保障的阶段流程处理失败。自动 DROP TABLE 不是无条件安全的补偿,表可能已经被其他请求使用,数据也可能已发生变化。
已经提交的数据要单独处理
发现问题后,先保留本次请求、SQL 顺序、事务范围和已提交记录的身份,停止无条件重放整批操作。删除、扣款或状态变更已经提交时,再调用一次 ROLLBACK 不会找回数据。
依据业务记录、历史数据与备份制定恢复方案,区分本次修改和随后正常写入。不要恢复整库快照覆盖后续数据,也不要只删新表就声称原业务状态已恢复。
修复后,在隔离副本验证业务 SQL 不再被 DDL 分割,正常提交符合预期,失败能回滚整笔需要原子性的写入。结构迁移另行检查实际对象和版本;框架没有抛异常与数据库原子性正确,是两项不同的验收。


