MySQL 事物 - 学习笔记
前言
在梳理 MySQL 事物和锁这一块知识的时候,发现其实自己了解的只是冰山一角,经过认真的查阅和研究之后,其实这一块的知识其实还真的有很多的学问。
所以后面还是需要研读一下《高性能 MySQL》这本书。
正文
谈到 MYSQL 的事物, 相信大家对这几个概念都不会陌生:
四大特性:ACID
并发问题
隔离级别
下面的思维导图可能更表达得清晰😏
MySQL 的默认事物隔离级别是 RR (Repeatable Read)
,可重复读级别是能够解决脏读、不可重复读的这两个事物并发问题的,但是幻读的问题仍会存在,如果使用Serializable
的隔离级别,对于高并发的业务来说是不实际的。那么 MySQL 是如何解决幻读这个棘手的问题呢?
没错,MySQL 通过MVCC
(多版本并发控制)和Gap Lock
(间隙锁)这两个机制解决了幻读的问题~
那么这两种方式具体又是如何实现的呢?
这里我们先讲一下 MySQL 的"读"的区别。因为在事物隔离级别中的"读",分为快照读(snapshot read)
和当前读(current read)
1. 当前读(current read)
select...lock in share mode (共享读锁)select...for updateupdate , delete , insert
读取的是最新的数据,并且对读取的记录加锁,阻塞其他事物对当前事物查询数据的修改和插入,从而解决幻读。
实现方式:Next-key Locks(临键锁)
官方对临键锁的定义是:
A next-key lock is a combination of a record lock on the index record and a gap lock on the gap before the index record.
简单来说就是 临键锁 = 行记录锁 + 间隙锁
行锁、间隙锁这个锁的概念,下文会介绍。所以这里我们只要知道的是,对于事物的当前读模式,是通过 Gap-Key-Locks 解决的。
2. 快照读(snapshot read)
select * from table
单纯的 select 操作
Read Committed 隔离级别:每次 select 都生成一个快照读。
Read Repeatable 隔离级别:开启事务后第一个 select 语句才是快照读的地方,而不是一开启事务就快照读。
实现方式:undolog 和 MVCC
undolog 用于数据的撤回操作,它记录了修改的反向操作,比如,插入对应删除,修改对应修改为原来的数据,通过 undo log 可以实现事务回滚,并且可以根据 undo log 回溯到某个特定的版本的数据。
MVCC 就是上文提到的多版本并发控制。
实现方式
MVCC
MVCC 只是工作在两种事务级别底下:
Read Committed
Repeatable Read
MVCC 每行记录后面保存三个隐藏的列,其中其主要作用的有两列
DB_TRX_ID: 记录行数据创建时的事物版本号。每开启一个事物,事物版本号都会递增。
DB_ROLL_PTR: 记录行数据何时过期(或者被删除)。指向前一个版本的 undolog 记录,组成 undo 链表。如果更新了行,则撤消日志记录包含在更新行之前重建行内容所需的信息。
INSERT
DELETE
UPDATE
SELECT
Record Locks(行锁)
官方对行锁的定义是:
A record lock is a lock on an index record. For example,
SELECT c1 FROM t WHERE c1 = 10 FOR UPDATE;
prevents any other transaction from inserting, updating, or deleting rows where the value oft.c1
is10
.
简单来说,就是一个排他锁,以阻止其他事务插入,更新,删除。
Gap Locks(间隙锁)
官方对间隙锁的定义是:
A gap lock is a lock on a gap between index records, or a lock on the gap before the first or after the last index record. For example,
SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;
prevents other transactions from inserting a value of15
into columnt.c1
, whether or not there was already any such value in the column, because the gaps between all existing values in the range are locked.
举一个简单的例子:A、B、C 三个同学排队依次站成一排,此时新来了一个 E 同学,那要如何才能不让 E 同学插队呢。其实把 A、B、C 三个人的间隙都封锁上,这样子 E 就不能穿插进来了。而这个锁也就可以理解为间隙锁。
当然,间隙锁也是有条件的:
使用普通索引锁定;
使用多列唯一索引;
使用唯一索引锁定多行记录;
Next-key Locks(临键锁)
上文也提到了 临键锁 = 行锁 + 间隙锁,其实也就是它即锁定了当前行,也锁定范围区间。
总结
MySQL 的默认隔离级别
Repeatable Read
,RR 级别下会存在幻读问题,但是 MySQL 通过MVCC
和Gap Locks
解决幻读问题。MySQL 在事务隔离级别下的读取方式有两种:快照读和当前读
对于快照读来说,幻读的解决是依赖
MVCC
解决;而对于当前读则依赖于Gap Locks
解决Gap Lock 在 InnoDB 的唯一作用就是防止其他事务的插入操作,以此防止幻读的发生
MVCC 通过版本号来处理事务,防止加锁,来提高访问效率
版权声明: 本文为 InfoQ 作者【Edison】的原创文章。
原文链接:【http://xie.infoq.cn/article/1550f3ad99709efad3b1be499】。文章转载请联系作者。
评论