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表),避免业务逻辑里出现无意义的长时间持锁或交互等待。
