一致性非锁定读(Consistent nonlocking read)
指InnoDB存储引擎通过多版本控制的方法来读取当前执行时间数据库中行的数据。如果读取的数据行正在执行delete或update操作,这时读取不会因此去等待行上锁 的释放。相反InnoDB存储引擎会去读取一个快照数据。
之所以成为非锁定读,因为这种方式不需要等待访问行上的排他锁的释放。
快照数据(当前行数据之前的历史版本),每行记录可能有多个版本。
-
MVCC实现是通过undo日志实现的,当一条记录被修改时,当前的老版本数据会作为一条undo记录保存在undo log(回滚日志)中。
-
读快照数据是不需要上锁的,因为没有事务需要对历史的数据进行修改操作。
-
可重复读事务隔离级别下,对于快照数据,非锁定一致读总是读取事务开始时的行数据版本。
-
READ COMMITED事务隔离级别下,总是读取最新的快照数据。
快照数据,是事务已提交后的数据,可能是其它事务已提交的的数据。
比如说 表内数据num = 1;
A事务 B事务
begin
get num = 1
begin
set num = num + 1
get num = 2
commit
get num <-------------------------------------------- 如果RR级别,则 num = 1
如果RC级别,则 num = 2
set num = num + 1 <-------------------------------update执行成功,返回1
get num <-----------------------------------------------如果RR级别,则 num = 3
如果RC级别,则 num = 3
比如说 表内数据num = 1;
A事务 B事务
begin
get num = 1
begin
set num = num + 1
get num = 2
commit
get num <-------------------------------------------- 如果RR级别,则 num = 1
如果RC级别,则 num = 2
set num = num + 1 where num = 1 <-------------------------------update执行失败,返回0
get num <-----------------------------------------------如果RR级别,则 num = 1
如果RC级别,则 num = 2
比如说 表内数据num = 1;
A事务 B事务
begin
begin
update table set <-------------------------------------------获取id=id1那一行的排他锁
num = num + 1 where id = id1;
update table set <--------id1行排他锁正在被事务A占用,
num = num + 1 where id = id1; 事务B阻塞等待
commit; <-------------------------------------------- 释放id=id1那一行的排他锁
等到事务A释放掉id1行的排他锁,
事务B就可以尝试获取到id1行的排他锁并执行update更新语句。
commit; <--- 释放id=id1那一行的排他锁
总结:
-
update语句中的where查询 语句 读取的都是最新的快照数据,最新的提交数据(无论在RR级别还是在RC级别都是这样的机制)
-
select语句中的where查询语句(不加 共享锁或排他锁的情况下)RR级别下在同一个事务中,读到的数据是事务刚开始是的快照数据(不会幻读,同一查询语句在同一事务中得到结果相同)或者是在本事务中对数据进行的最新修改,RC级别下,同一个事务中读到的是当前最新的快照版本数据(其它事务对这数据已提交的修改,会出现幻读)或者是在本事务中对数据进行的最新修改。
-
update语句相当于获取排他锁,未获得锁的事务只能等待。