写点什么

MySQL 事物 - 学习笔记

用户头像
Edison
关注
发布于: 2020 年 08 月 07 日
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 of t.c1 is 10.


简单来说,就是一个排他锁,以阻止其他事务插入,更新,删除。


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 of 15 into column t.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 就不能穿插进来了。而这个锁也就可以理解为间隙锁。


当然,间隙锁也是有条件的:


  1. 使用普通索引锁定;

  2. 使用多列唯一索引;

  3. 使用唯一索引锁定多行记录;


Next-key Locks(临键锁)


上文也提到了 临键锁 = 行锁 + 间隙锁,其实也就是它即锁定了当前行,也锁定范围区间。


总结


  1. MySQL 的默认隔离级别 Repeatable Read,RR 级别下会存在幻读问题,但是 MySQL 通过 MVCCGap Locks 解决幻读问题。

  2. MySQL 在事务隔离级别下的读取方式有两种:快照读和当前读

  3. 对于快照读来说,幻读的解决是依赖 MVCC 解决;而对于当前读则依赖于 Gap Locks 解决

  4. Gap Lock 在 InnoDB 的唯一作用就是防止其他事务的插入操作,以此防止幻读的发生

  5. MVCC 通过版本号来处理事务,防止加锁,来提高访问效率


发布于: 2020 年 08 月 07 日阅读数: 86
用户头像

Edison

关注

还未添加个人签名 2018.05.18 加入

还未添加个人简介

评论

发布
暂无评论
MySQL事物-学习笔记