从零开始学习MySQL(七) – 浅谈MySQL锁机制

第七章 浅谈 MySQL 锁机制 *

在MySQL中,就很容易出现多线程同时操作表中数据的情况,如果要避免潜在的并发问题,那么我们可以使用之前讲解的事务隔离级别来处理,而事务隔离中利用了锁机制。

  • 读未提交(Read Uncommitted):能够读取到其他事务中未提交的内容,存在脏读问题。
  • 读已提交(Read Committed RC):只能读取其他事务已经提交的内容,存在不可重复读问题。
  • 可重复读(Repeated Read RR):在读取某行后不允许其他事务操作此行,直到事务结束,但是依然存在幻读问题。
  • 串行读(Serializable):一个事务的开始必须等待另一个事务的完成。

我们可以切换隔离级别分别演示一下:

set session transaction isolation level read uncommitted;

在RR级别下,MySQL在一定程度上解决了幻读问题:

  • 在快照读(不加锁)读情况下,MySQL 通过 MVCC 来避免幻读。
  • 在当前读(加锁)读情况下,MySQL 通过next-key来避免幻读。

MVCC,全称 Multi-Version Concurrency Control ,即多版本并发控制。MVCC 是一种并发控制的方法,一般在数据库管理系统中,实现对数据库的并发访问,在编程语言中实现事务内存。

第一节 读锁和写锁

从对数据的操作类型上来说,锁分为读锁和写锁:

  • 读锁:也叫共享锁,当一个事务添加了读锁后,其他的事务也可以添加读锁或是读取数据,但是不能进行写操作,只能等到所有的读锁全部释放。
  • 写锁:也叫排他锁,当一个事务添加了写锁后,其他事务不能读不能写也不能添加任何锁,只能等待当前事务释放锁。

第二节 全局锁、表锁和行锁

从锁的作用范围上划分,分为全局锁、表锁和行锁:

  • 全局锁:锁作用于全局,整个数据库的所有操作全部受到锁限制。
  • 表锁:锁作用于整个表,所有对表的操作都会收到锁限制。
  • 行锁:锁作用于表中的某一行,只会通过锁限制对某一行的操作(仅InnoDB支持)

1. 全局锁

我们首先来看全局锁,它作用于整个数据库,我们可以使用以下命令来开启读全局锁:

FLUSH TABLES WITH READ LOCK;

开启后,整个数据库被上读锁,我们只能去读取数据,但是不允许进行写操作(包括更新、插入、删除等)一旦执行写操作,会被阻塞,直到锁被释放,我们可以使用以下命令来解锁:

UNLOCK TABLES;

除了手动释放锁之外,当我们的会话结束后,锁也会被自动释放。

2. 表锁

表锁作用于某一张表,也是MyISAM和InnoDB存储引擎支持的方式,我们可以使用以下命令来为表添加锁:

LOCK TABLE 表名称 READ/WRITE;

在我们为表添加写锁后,我们发现其他地方是无法访问此表的,一律都被阻塞。

3. 行锁

表锁的作用范围太广了,如果我们仅仅只是对某一行进行操作,那么大可不必对整个表进行加锁,因此InnoDB支持了行锁,我们可以使用以下命令来对某一行进行加锁:

-- 添加读锁(共享锁)
SELECT * FROM ... LOCK IN SHARE MODE;
-- 添加写锁(排他锁)
SELECT * FROM ... FOR UPDATE;

使用InnoDB的情况下,在执行更新、删除、插入操作时,数据库也会自动为所涉及的行添加写锁(排他锁),直到事务提交时,才会释放锁,执行普通的查询操作时,不会添加任何锁。使用MyISAM的情况下,在执行更新、删除、插入操作时,数据库会对涉及的表添加写锁,在执行查询操作时,数据库会对涉及的表添加读锁。

提问:当我们不使用索引列进行选择,行锁会发生什么变化?(行锁升级)

如果没有走索引,引擎就无法得知SELECT语句到查询的是哪一行不,行锁就会升级为全表锁(本质为记录锁)。

第三节 记录锁、间隙锁和临键锁

我们知道InnoDB支持使用行锁,但是行锁比较复杂,它可以继续分为多个类型。

1. 记录锁

(Record Locks)记录锁, 仅仅锁住索引记录的一行,在单条索引记录上加锁。Record lock锁住的永远是索引,而非记录本身,即使该表上没有任何索引,那么 InnodDB 会在后台创建一个隐藏的聚集主键索引,那么锁住的就是这个隐藏的聚集主键索引。所以说当一条sql没有走任何索引时,那么将会在每一条聚合索引后面加写锁,这个类似于表锁,但原理上和表锁应该是完全不同的。

2. 间隙锁

(Gap Locks)仅仅锁住一个索引区间(开区间,不包括双端端点)。在索引记录之间的间隙中加锁,或者是在某一条索引记录之前或者之后加锁,并不包括该索引记录本身。比如在 1、2中,间隙锁的可能值有 (-∞, 1),(1, 2),(2, +∞),间隙锁可用于防止幻读,保证索引间的不会被插入数据。

3. 临键锁

(Next-Key Locks)Record lock + Gap lock,左开右闭区间。默认情况下,InnoDB正是使用Next-key Locks来锁定记录(如select … for update语句)它还会根据场景进行灵活变换:

场景 转换
使用唯一索引进行精确匹配,但表中不存在记录 自动转换为 Gap Locks
使用唯一索引进行精确匹配,且表中存在记录 自动转换为 Record Locks
使用非唯一索引进行精确匹配 不转换
使用唯一索引进行范围匹配 不转换,但是只锁上界,不锁下界

注:关于更多临键锁机制可以阅读此文章 MySQL的锁机制 - 记录锁、间隙锁、临键锁 - 知乎

暂无评论

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇