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