mysql innodb事务需显式关闭autocommit(set autocommit=0)后用start transaction开启,commit/rollback控制提交或回滚;ddl隐式提交事务;innodb_flush_log_at_trx_commit影响持久性;长事务阻塞undo清理,需监控innodb_trx。

MySQL InnoDB 的事务提交靠 COMMIT,回滚靠 ROLLBACK
InnoDB 默认开启自动提交(autocommit=1),每条 SQL 执行完立刻生效、不可撤销。要手动控制事务,必须先关闭它:SET autocommit = 0,再显式用 START TRANSACTION 或 BEGIN 开启事务块。此时后续的 DML(INSERT/UPDATE/DELETE)会暂存在事务私有版本链中,直到遇到 COMMIT 写入聚簇索引并释放锁,或 ROLLBACK 清空变更、恢复到事务开始前的快照。
事务能回滚的前提是:未被 COMMIT 且连接未断开
常见误解是“只要没关终端就能回滚”,其实关键在连接状态和事务活跃性:
-
ROLLBACK只对当前活跃事务有效;执行后事务结束,再执行ROLLBACK会报错ERROR 1370 (42000): execute command denied to user(实际是 “No transaction in progress” 类错误) - 客户端异常断连(如网络中断、kill 连接)、超时(
wait_timeout触发)会导致事务自动回滚,但不会通知应用层 - 如果事务中执行了 DDL(如
ALTER TABLE),InnoDB 会隐式提交当前事务,后续语句不在同一事务内 —— 此时ROLLBACK只能回滚 DDL 之后的 DML,无法撤回 DDL 本身
COMMIT 不等于“立刻刷盘”,取决于 innodb_flush_log_at_trx_commit
这个参数决定日志落盘时机,直接影响事务持久性和性能:
-
innodb_flush_log_at_trx_commit = 1(默认):每次COMMIT都触发fsync将 redo log 刷到磁盘,崩溃不丢事务,但 IO 压力大 -
= 0:每秒刷一次日志,事务提交只写内存,宕机可能丢失最多 1 秒数据 -
= 2:提交时写 OS cache,由系统异步刷盘,崩溃时若 OS 挂了仍可能丢数据
注意:无论设成几,COMMIT 返回成功即代表该事务已进入 InnoDB 的“已提交但未刷盘”状态,其他事务按隔离级别可见其结果(如可重复读下不可见,读已提交下可见)。
回滚段(undo log)不是无限空间,长事务容易撑爆 ibdata1
InnoDB 把旧版本数据存于 undo log,供 MVCC 和回滚使用。问题在于:
- 一个运行 10 分钟未提交的事务,会阻止所有早于它的 undo 记录被清理,导致
undo log持续增长 - 如果
innodb_undo_tablespaces未启用,undo 日志全挤在系统表空间ibdata1里,文件只增不减 -
SHOW ENGINE INNODB STATUS中的History list length值持续升高,就是 undo 积压的信号
线上应监控长事务(查 information_schema.INNODB_TRX 表),避免业务逻辑里出现无意义的长时间持锁或交互等待。










