本文是在看了何登成大神的技术博客后做的总结,部分图片来自其技术博客,主要是方便自己日后回顾,在此感谢原博客作者提供的经典之作,原作者博客地址:http://hedengcheng.com/?p=771#_Toc374698322。
一、什么是快照读与当前读
MVCC(多版本并发控制协议)在InnoDB存储引擎中主要提供两种读方式,一种是快照读,一种是当前读。
快照读:
所谓快照读就是一致性非锁定读,就是读取的是历史版本,不用加锁,提高并发,在数据库不同的隔离级别下读取的历史版本有所不同,在RR(REPEATABLE READ)隔离级别下读的历史版本总是事务刚开始的那一个版本,所以可以避免不可重复读与幻读,因为其对其他事务提交的数据是不可见的。在RC(READ COMMITTED)隔离级别下读的是最新的历史版本,或者是可见版本(另一个事务刚已经提交的数据),这样就会出现不可重复读现象。
SELECT * FROM table WHERE ........
当前读:
当前读时一致性锁定读,采取加锁的方法保证并发数据的一致性:
SELECT * FROM table WHERE ... LOCK IN SHARE MODE(加的是共享锁(S))
SELECT * FROM table WHERE ... FOR UPDATE(加的是排他锁(X))
INSERT INTO table ........ (在插入数据前先读取数据,进行唯一性检查,读取数据时会加X锁)
UPDATE table SET ......... (在更新数据之前得先读取数据,在对读取的数据进行修改,读取数据时会加X锁)
DELETE FROM table ........(在删除数据之前也是得先读取数据,读取数据时会对数据加X锁)
说明:在serializable隔离级别下,MVCC退化成了base-lock concurrency control(基于锁的并发控制),也就不存在快照读了,全是当前读,序列化的操作,并发性受到了很大的影响,一般不采用该隔离级别。
二、加锁分析的前提
对于sql加锁的分析,是有一些前提条件的,不能笼统的说加没加锁,加了什么锁。得看过滤条件是不是主键,如果不是主键,有没有索引,索引是否是唯一索引,当前数据库的隔离级别是什么,该sql语句的执行计划是什么(全表扫还是索引扫描)。以上这些就是所说的分析加锁的前提条件,在分析加锁时,得先判断是这些前提条件的那种组合。
对于快照读,也就是不加锁的方式,就不予分析了,对于当前读,选取delete from t1 where id = 10语句对九种组合进行加锁分析:
组合一:id列是主键,RC隔离级别
组合二:id是唯一索引,RC隔离级别
组合三:id是普通索引,非唯一,RC隔离级别
组合四:id没有索引,RC隔离级别
组合五:id是主键,RR隔离级别
组合六:id是唯一索引,RR隔离级别
组合七:id是普通索引,非唯一,RR隔离级别
组合八:id没有索引,RR隔离级别
组合九:serializable隔离级别
三、实例分析
1、组合一:id列是主键,RC隔离级别
表t1:
sql语句:DELETE FROM t1 WHERE id = 10
加锁情况见下图:
测试:
上图中指出了在这种组合下面会对相应的主键记录进行加锁,加的是record lock。
模拟事务A删除id为10的记录,未提交,事务B查询(当前读)id为10的记录,出现锁阻塞:
从上面可见对主键id进行了加锁处理。
2、组合二