1、锁

记录锁(Record Locks)

记录锁是 封锁记录,记录锁也叫行锁

间隙锁(Gap Locks)

间隙锁是封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。

产生间隙锁的条件:

1、innodb引擎且隔离级别为RR

2、使用普通索引锁定;

3、使用多列唯一索引;

4、使用唯一索引锁定多行记录。

Mysql MVCC解决了RR事务的可重复读问题,使用间隙锁解决了RR级别的幻读问题

临键锁(Next-key Locks)

临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。

注:临键锁的主要目的,也是为了避免幻读(Phantom Read)。如果把事务的隔离级别降级为RC,临键锁则也会失效。

记录锁、间隙锁、临键锁都是排它锁

当前读、快照读

·快照读也叫普通读,就是单纯的select 语句,不包括下面这两类语句:

SELECT ... FOR UPDATE 
SELECT ... LOCK IN SHARE MODE

普通读的执行方式是生成 ReadView,直接利用 MVCC 机制来进行读取,并不会对记录进行加锁。

·当前读:读取的是最新版本,并且需要先获取对应记录的锁,当前读是通过 next-key 锁(行记录锁+间隙锁)来是实现的。如以下这些 SQL 类型:

select ... lock in share mode 、 select ... for update、 update 、delete 、insert

获取什么类型的锁取决于当前事务的隔离级别、语句的执行计划、查询条件等因素。例如,要 update 一条记录,在事务执行过程中,如果不加锁,那么另一个事务可以 delete 这条数据并且能成功 commit ,就会产生冲突了。所以 update 的时候肯定要是当前读,得到最新的信息并且锁定相应的记录。

总结

  1. 记录锁、间隙锁、临键锁,都属于排它锁;
  2. 记录锁就是锁住一行记录;
  3. 间隙锁只有在事务隔离级别 RR 中才会产生;
  4. 唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁;
  5. 普通索引不管是锁住单条,还是多条记录,都会产生间隙锁;
  6. 间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,这是为了防止出现 幻读 现象;
  7. 普通索引的间隙,优先以普通索引排序,然后再根据主键索引排序(多普通索引情况还未研究);
  8. 事务级别是RC(读已提交)级别的话,间隙锁将会失效。
  9. 快照读的幻读,靠mvcc+readview解决,readview生成后不会刷新。
  10. 当前读的幻读,靠主键锁和间隙锁解决,所以仅靠mvcc解决不了幻读

2、mvcc:(这本书写的不错,很详细)

mysql 记录锁间隙锁临键锁 间隙锁 临键锁 记录锁_间隙锁

mysql 记录锁间隙锁临键锁 间隙锁 临键锁 记录锁_记录锁_02

mysql 记录锁间隙锁临键锁 间隙锁 临键锁 记录锁_mysql 记录锁间隙锁临键锁_03

mysql 记录锁间隙锁临键锁 间隙锁 临键锁 记录锁_mysql 记录锁间隙锁临键锁_04

mysql 记录锁间隙锁临键锁 间隙锁 临键锁 记录锁_记录锁_05

mysql 记录锁间隙锁临键锁 间隙锁 临键锁 记录锁_mysql_06

mysql 记录锁间隙锁临键锁 间隙锁 临键锁 记录锁_mysql 记录锁间隙锁临键锁_07

mysql 记录锁间隙锁临键锁 间隙锁 临键锁 记录锁_mvcc_08

mysql 记录锁间隙锁临键锁 间隙锁 临键锁 记录锁_间隙锁_09

mysql 记录锁间隙锁临键锁 间隙锁 临键锁 记录锁_记录锁_10