mysql事务回滚失效主因是ddl隐式提交:执行alter table等ddl前,select @@in_transaction值为1,执行后变为0,证实事务已被强制提交;create、drop、grant等语句同理,须通过运行时状态验证而非代码逻辑判断。

事务回滚失效,先确认是不是被隐式提交了
直接查 SELECT @@in_transaction; —— 如果执行 DDL(比如 ALTER TABLE)前后这个值从 1 变成 0,基本就能锁定是隐式提交。MySQL 8.0+ 中这个变量最直观;老版本可用 SELECT @@autocommit, @@tx_isolation; 辅助判断,但不如 @@in_transaction 可靠。
别只看代码有没有写 BEGIN 或 @Transactional,很多问题出在“你以为还在事务里,其实早就提交了”。常见触发点包括:CREATE、DROP、ALTER、TRUNCATE、GRANT、REVOKE、LOCK TABLES,甚至存储过程中动态拼的 PREPARE/EXECUTE DDL 语句。
DDL 执行前,怎么知道当前事务还“活着”
不能靠肉眼扫 SQL,得靠运行时状态验证。关键操作是:
- 执行 DDL 前,立刻查
SELECT TRX_ID, TRX_STATE FROM information_schema.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID();—— 如果返回一行且TRX_STATE = 'RUNNING',说明事务确实在跑 - 执行 DDL 后,马上再查
@@in_transaction,值变为 0 就实锤被切开了 - 应用层(如 Python 的
mysql-connector-python)可在关键位置加日志:记录conn.get_autocommit()和conn.in_transaction(),比只打 SQL 更早暴露问题
Navicat/DBeaver 里多语句执行容易踩的坑
图形客户端默认勾选“自动提交”,但更危险的是:它把多条语句当一个批次发过去,而 MySQL 服务端仍按单条解析执行。结果就是 —— INSERT 在事务中,ALTER TABLE 碰上就立刻提交,后面 ROLLBACK 对前面的 INSERT 完全无效。
排查方法很简单:
- 关掉客户端的“自动提交”选项(但注意:这不影响 DDL 的隐式提交行为)
- 把 DDL 单独拆成独立查询窗口执行,和业务 DML 物理隔离
- 用命令行
mysql -e "BEGIN; INSERT ...; ALTER TABLE ...; ROLLBACK;"复现,能更快暴露问题
为什么 SHOW WARNINGS 能帮上大忙
隐式提交本身不报错,但触发它的操作(比如 DDL 失败、触发器报错、字符集不匹配)往往静默失败,错误信息藏在 SHOW WARNINGS 里,而不是主 SQL 返回值中。
典型场景:
- 执行完疑似失败的
INSERT后,立刻执行SHOW WARNINGS,可能看到Warning 1366 Incorrect string value—— 实际是 DML 已失败,事务中断,后续COMMIT报ERROR 1373 - 触发器里字段名写错,
INSERT返回“成功”,但查表没数据,SHOW WARNINGS显示Unknown column 'xxx' in 'NEW' - 错误日志里要开
log_error_verbosity = 3,否则这些警告不会落盘
真正难缠的不是 DDL 本身,而是它和业务逻辑混在一起时,错误信号被稀释、延迟或吞掉。盯住 @@in_transaction 和 SHOW WARNINGS 这两个点,比翻十几层堆栈更管用。











