mysql InnoDB存储引擎如何支持事务_mysql事务实现原理

来源:这里教程网 时间:2026-02-28 20:47:19 作者:

事务的ACID特性在InnoDB中靠什么落地

InnoDB不是靠“声明式支持”来提供事务,而是用一套协同工作的底层机制硬实现的:redo log 保证持久性(D),undo log 保证原子性(A)和一致性(C),而行级锁 + MVCC 一起支撑隔离性(I)。这四者缺一不可,删掉任意一个,

START TRANSACTION
就只剩个空壳。

redo log 和 binlog 的分工与协作

很多人误以为

commit
成功 = 数据已刷盘。实际是:事务提交时,InnoDB 只确保
redo log
写入磁盘(由
innodb_flush_log_at_trx_commit
控制),而数据页(
ibd
文件)可能还在 buffer pool 中延迟写入。这样既快又安全——崩溃后可用 redo log 重放已提交但未落盘的变更。

binlog
是 Server 层日志,不参与崩溃恢复,只用于主从复制和归档。MySQL 用两阶段提交(2PC)协调二者:
prepare
阶段写 redo log 并标记为 prepared;
commit
阶段先写 binlog,再将 redo log 标记为 commit。任一环节失败,crash recovery 都能靠这个状态判断是否回滚。

undo log 如何支撑回滚和 MVCC

每次

UPDATE
DELETE
,InnoDB 不直接覆盖旧数据,而是把原记录写进
undo log
,并用
roll_pointer
指向它。这样:

执行
ROLLBACK
时,顺着
roll_pointer
链一路恢复即可
其他事务做
SELECT
时,根据自己的
read view
判断该读哪个版本——这就是 MVCC 的核心。注意:
READ COMMITTED
每条语句都生成新
read view
,而
REPEATABLE READ
在事务第一次
SELECT
时就固定住
read view
purge
线程异步清理已无事务需要的 undo log,否则
ibdata1
会持续膨胀

行锁、间隙锁与死锁检测的真实开销

InnoDB 默认加的是

next-key lock
(行锁 + 间隙锁),不是单纯的“某一行被锁”。比如
WHERE id = 5
在唯一索引上才可能是纯行锁;若查的是非唯一索引或范围条件(如
WHERE age BETWEEN 20 AND 30
),就会锁住索引间隙,防止幻读——这也意味着并发插入可能被意外阻塞。

死锁检测由

innodb_deadlock_detect
控制,默认开启。一旦触发,InnoDB 会主动回滚代价最小的事务(按
undo log
大小估算)。但高并发下频繁检测本身有 CPU 开销;关掉它虽省资源,却要靠
innodb_lock_wait_timeout
超时被动退出,响应更不可控。

真正容易被忽略的是:唯一索引等值查询(

=
)且记录存在时,InnoDB 才会优化为仅加 record lock;只要记录不存在,哪怕条件唯一,也会退化为 gap lock —— 这点在设计防重逻辑时经常踩坑。

相关推荐