(点击
上方公众号
,可快速关注)
来源:伯乐在线专栏作者 - 陆晨
链接:
http://blog.jobbole.com/108804/
点击 → 了解如何加入专栏作者
背景
innodb存储引擎实现了两种标准的行级锁:S锁和X锁,S锁被称为共享锁,允许事务读一行数据,X锁被称为排它锁,允许事务删除或更新一行数据。
一致性非锁定读指的是如果一条记录被加了X锁,其他事务还能读取这条记录。
一致性锁定读指的是一个事务可以通过SELECT语句给某条记录加X锁或者X锁。
一个小栗子
我们假设有一个表和两个事务,表名字为mytest,事务名字为t1和t2:
t1和t2的执行时序如下:
这里我先抛出两个问题:
-
上面Mark A处显然t1已经给记录加了X锁,并且在事务内修改了数据,此时t2看到的数据是什么?
-
上面Mark B处事务t1已经提交此时t2看到的数据是什么?
行多版本控制
行多版本将的是innodb为每个行记录存储了多个版本,记住,这里是多个版本不是两个版本,在刚开始接触多版本的时候,我的疑问是innodb对每个行要存储多个版本是多么浪费存储空间呀?然而进一步了解,原来所谓的多版本只是innodb聪明地撒了个谎,多个版本是通过undo日志实现的,这里可以理解为既然undo日志包括了所有用来恢复历史版本数据的信息,那么我们只要将“不同版本”指针指向不同时间节点的undo日志即可,这样读取的时候通过对不同时间节点的undo日志进行恢复从而得到不同的版本数据。同时对于undo日志的读取是不需要加锁的,因此这极大地提高了数据库的并发性。
这里回答了上面的第一个问题:t2此时看到的应该是历史版本的数据,也就是t1修改之前的数据,如下:
mysql
>
select *
from mytest where
t2
=
'bb'
;
+------+------+------+------+
|
t1
|
t2
|
t3
|
t4
|
+------+------+------+------+
|
a
|
bb
|
bb
|
ccc
|
+------+------+------+------+
1
row
in
set
(
0.00
sec
)
READ COMMITTED 与 REPEATABLE READ
这里复习一下SQL标准定义的四个隔离级别分别为:
-
READ UNCOMMITTED
-
READ COMMITTED
-
REPEATABLE READ
-
SERIALIZABLE
innodb默认的隔离级别为REPEATABLE READ且使用next key locking技术解决的幻读的问题,READ COMMITTED值的是一个事务可以读取其他事务已经提交的数据,而REPEATABLE READ要求一个事务在事务内可以重复读取一条记录,因此上面第二个问题的答案是此时t2看到的是什么跟此时数据库的隔离级别有关系,比如此时的隔离级别为:
mysql
>
select
@@
tx_isolation
;
+-----------------+
|
@@
tx
_
isolation
|
+-----------------+
|
REPEATABLE
-
READ
|
+-----------------+
1
row
in
set
(
0.00
sec
)
因此t2在Mark B的地方看到的应该是老数据:
mysql
>
select *
from mytest where
t2
=
'bb'
;
+------+------+------+------+
|
t1
|
t2
|
t3
|
t4
|
+------+------+------+------+
|
a
|
bb
|
bb
|
ccc
|
+------+------+------+------+
1
row
in
set
(
0.00
sec
)
mysql
>
如果此时的事务隔离级别为READ COMMITTED,则t2在Mark B处看到的应该是新数据。
一致性锁定读
一致性非锁定读的情况下即使记录因为UPDATE而被加了X锁,其他事务仍然能够读取记录,不会阻塞。而如果一个事务希望在读取的时候就把记录锁住,不允许其他事务进行修改应该怎么做呢?那就是SELECT … FOR UPDATE,SELECT … FOR UPDATE显式地给一条记录加X锁,因此其他事务不能获取该记录的任何锁。我们也可以使用SELECT … LOCK IN SHARE MODE来给记录显式地加S锁,因此其他事务能够获取该记录的S锁而不能获取该记录的X锁,这两种语句都是有特定的应用场景的。
总结
再总结一下,一致性非锁定读讲的是一条记录被加了X锁其他事务仍然可以读而不被阻塞,是通过innodb的行多版本实现的,行多版本并不是实际存储多个版本记录而是通过undo实现。一致性锁定读讲的是我可以通过SELECT语句显式地给一条记录加X锁从而保证特定应用场景下的数据一致性。
觉得本文有帮助?请分享给更多人
关注「数据库开发」
看更多精选技术干货
专栏作者简介
(
点击 → 加入专栏作者
)
陆晨:
开源技术爱好者,专注JAVA技术、中间件技术研究与分享
。
打
赏支持作者写出更多好文章,谢谢!