事务的介绍看这篇博客: MySQL架构基础
并发控制的介绍看这篇博客: InnoDB并发控制
本篇博客介绍InnoDB的四种事务隔离级别是如何实现的, 需要事先阅读上面的两篇博客.
REPEATABLE READ
InnoDB并发控制 这篇博客最后一部分对REPEATABLE READ隔离级别是如何实现做了详细介绍, 这里做个简单的归纳.
普通的SELECT
快照读, 即不加锁的一致性读. 在同一个事务中, 所有的select操作都是读取的第一次select所建立的快照, 这就解决了不可重复读的问题.
加锁SELECT/UPDATE/DELETE
(1)在唯一索引(PRIMARY KEY和UNIQUE KEY) 上使用唯一的查询条件时, 加记录锁.
(2)其他情况使用间隙锁或者临键锁(InnoDB使用的是临键锁, 因为间隙锁可以被显示禁用). 间隙锁和临键锁解决了幻读的问题.
INSERT
在插入索引间隔内加插入意向锁, 对具体的插入行加记录锁.
READ COMMITTED
普通的SELECT
快照读, 即不加锁的一致性读. 与REPEATABLE READ隔离级别不同的是, 每一次一致性读取, 即使在同一事务中, 也会设置和读取它自己的新快照, 这就会导致不可重复读的问题.
快照读解决了脏读的问题.
加锁SELECT/UPDATE/DELETE
除了在外键约束检查(foreign-key constraint checking)以及重复键检查(duplicate-key checking)时会封锁区间, 其他时刻都只使用记录锁, 这就会导致幻读的问题.
INSERT
在插入索引间隔内加插入意向锁, 对具体的插入行加记录锁.
READ UNCOMMITTED
与READ COMMITTED的差别在于, 该隔离级别下没有使用快照读, 而是以不加锁的方式执行SELECT语句, 这就会导致脏读问题.
SERIALIZABLE
该隔离级别与REPEATABLE READ类似, 只有一点区别: 当禁用 autocommit 时, InnoDB会把普通的SELECT隐式地转换成SELECT … LOCK IN SHARE MODE. 这就会导致一个问题, 当有未提交的事务正在修改某些行,所有读取这些行的select都会被阻塞住(读写不能并发进行).