0%

MySQL笔记[InnoDB]一致性锁定和非锁定读

一、一致性非锁定读

​ 一致性非锁定读(consistent nonlocking read)是指InnoDB引擎通过行多版本控制(multi versioning)的方式来当前执行时间数据库中的行。如果读取的行正在执行update/delete操作,此时读操作不会等待锁的释放,而是读取了行的快照。

innodb46

该方案是通过Undo段来实现的。Undo 段主要用于事务中回滚数据。快照数据就是当前行数据的历史版本,每个记录可以有多个版本。由此带来的并发控制,称为多版本并发控制(Multi Version Concrrency Controll,MVCC).

在事务隔离级别为READ COMMITED和REPEATABLE READ的事务隔离级别下,InnoDB引擎使用的是一致性非 锁定读。在READ COMMIT隔离级别下,对于快照数据,非一致性读总是读取被锁定行的最新一份数据快照;而REPEATABLE READ级别下,对于快照数据,非一致性读总是读取事务开始时的行数据版本。

例如以下例子:

在会话A中执行以下SQL:

BEGIN;

SELECT * FROM t4 WHERE a=1;

然后打开会话B,执行以下SQL:

BEGIN ;

UPDATE t4 SET a=3 WHERE a=1;

此时,在会话B中加了一个X锁,如果在会话A中再次执行SELECT * FROM t4 WHERE a=1;由于非锁定一致性读,在READ COMMIT和REPEATABLE READ下,都得到以下结果:

innodb47

此时,回到会话B,提交事务:

COMMIT;

SELECT @@tx_isolation;

innodb48

SELECT * FROM t4 WHERE a=1;后的结果为空。

此时在会话A中执行SELECT * FROM t4 WHERE a=1发现:

innodb49

读取的还是事务开始时的版本。把A会话的事务提交后,再查询,结果就和B一样的了。

这是REPEATABLE READ事务隔离级别的情况,如果是READ COMMITED级别中,在会话没提示事务之前,查询到的结果是和B一样的,是数据已经查询不到了,这违反了事务ACID的I特征,即隔离性。

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;

SELECT @@tx_isolation;

innodb50

二、一致性锁定读

InnoDB引擎对于SELECT语句一般支持两种一致性的锁定读操作:
• SELECT … FOR UPDATE;
• SELECT … LOCK IN SHARE MODE;
第一种加X锁,第2种加S锁,对于一致性非锁定读,即使行被执行了FOR UPDATE,也是可以进行行读取的。这两种方式必须在同一个事务中,即在BEGIN,START TRANSACTION或AUTOCOMMIT=0.


参考《MySQL技术内幕 -InnoDB存储引擎》整理,如侵权请联系vinin@163.com