限时领|《AI 百问百答》专栏课+实体书(包邮)! 了解详情
写点什么

Mysql 锁:灵魂七拷问

  • 2020-03-15
  • 本文字数:1892 字

    阅读完需:约 6 分钟

Mysql 锁:灵魂七拷问

一、缘起

假设你想给别人说明,Mysql 里面是有锁的,你会怎么做?


大多数人,都会开两个窗口,分别起两个事务,然后 update 同一条记录,在发起第二次 update 请求时,block,这样就说明这行记录被锁住了:


二、禁锢

问题来了,貌似只有显式的开启一个事务,才会有锁,如果直接执行一条 update 语句,会不会加锁呢?


比如直接执行:


update t set c = c + 1 where id = 1;
复制代码


这条语句,前面不加 begin,不显式开启事务,那么 Mysql 会不会加锁呢?


直觉告诉你,会。


但是为什么要加锁?


给你五秒钟,说出答案。



学过多线程和并发的同学,都知道下面这段代码,如果不加锁,就会有灵异事件:


i++;
复制代码


开启十个线程,执行 1000 次这段代码,最后 i 有极大可能性,会小于 1000。


这时候,用 Java 的套路,加锁:


synchornize {  i++;}
复制代码


问题解决。


同理,对于数据库,你可以理解为 i,就是数据库里的一行记录,i++ 这段代码,就是一条 update 语句,而多线程,对应的就是数据库里的多个事务。


既然对内存中 i 的操作需要加锁,保证并发安全,那么对数据库的记录进行修改,也必须加锁。


这道理很简单,但是很多人,未曾想过。

三、释然

为什么大家都喜欢用第一部分里的例子来演示 Mysql 锁?


因为开两个事务,会 block,够直观。


那么问题又来了,为什么会 block,或者说,为什么 Mysql 一定要等到 commit 了,才去释放锁?


执行完一条 update 语句,就把锁释放了,不行吗?


举个例子就知道 Mysql 为什么要这么干了:



一开始数据是:{id:1,c:1};


接着事务 A 通过 select … for update,进行当前读,查到了 c=1;


接着它继续去更新,把 c 更新成 3,假设这时候,事务 A 执行完 update 语句后,就把锁释放了;


那么就有了第 4 行,事务 B 过来更新,把 c 更新成 4;


结果到了第 5 行,事务 A 又来执行一次当前读,读到的 c,竟然是 4,明明我上一步才把 c 改成了 3…


事务 A 不由的发出怒吼:我为什么会看到了我不该看,我也不想看的东西?!


事务 B 的修改,居然让事务 A 看到了,这明目张胆的违反了事务 ACID 中的 I,Isolation,隔离性(事务提交之前,对其他事务不可见)。


所以,结论:Mysql 为了满足事务的隔离性,必须在 commit 才释放锁。

四、自私的基因

有人说,如果我是读未提交( Read Uncommited )的隔离级别,可以读到对方未提交的东西,是不是就不需要满足隔离性,是不是就可以不用等到 commit 才释放锁了?


非也。


还是举例子:



事务 A 是 Read Committed,事务 B 是 Read Uncommitted;


事务 B 执行了一条 update 语句,把 c 更新成了 3


假设事务 B 觉得自己是读未提交,就把锁释放了


那这时候事务 A 过来执行当前读,读到了 c 就是 3


事务 A 读到了别的事务没有提交的东西,而事务 A,还说自己是读已提交,真是讽刺


根因在于,事务 B 非常自私,他觉得自己是读未提交,就把锁释放了,结果让别人也被“读未提交”


显然,Mysql 不允许这么自私的行为存在。


结论:就算你是读未提交,你也要等到 commit 了再释放锁。

五、海纳百川

都知道 Mysql 的行锁,分为 X 锁和 S 锁,为什么 Mysql 要这么做呢?


这个简单吧,同样可以类比 Java 的读写锁:


It allows multiple threads to read a certain resource, but only one to write it, at a time.


允许多个线程同时读,但只允许一个线程写,既支持并发提高性能,又保证了并发安全。

六、凤凰涅磐

最后来个难点的。


假设事务 A 锁住了表 T 里的一行记录,这时候,你执行了一个 DDL 语句,想给这张表加个字段,这时候需要锁表吧?但是由于表里有一行记录被锁住了,所以这时候锁表时会 block。


那 Mysql 在锁表时,怎么判断表里有没有记录被锁住呢?


最简单暴力的,遍历整张表,遍历每行记录,遇到一个锁,就说明表里加锁了。


这样做可以,但是很傻,性能很差,高性能的 Mysql,不允许这样的做法存在。


Mysql 会怎么做呢?


行锁是行级别的,粒度比较小,好,那我要你在拿行锁之前,必须先拿一个假的表锁,表示你想去锁住表里的某一行或者多行记录。


这样,Mysql 在判断表里有没有记录被锁定,就不需要遍历整张表了,它只需要看看,有没有人拿了这个假的表锁。


这个假的表锁,就是我们常说的,意向锁。


Intention locks are table-level locks that indicate which type of lock (shared or exclusive) a transaction requires later for a row in a table


很多人知道意向锁是什么,但是却不知道为什么需要一个粒度比较大的锁,不知道它为何而来,不知道 Mysql 为何要设计个意向锁出来。


知其然,知其所以然。

七、参考文献


2020-03-15 20:19876

评论

发布
暂无评论
发现更多内容

安全性和合规性:保障企业数据的安全

可观测技术

数据安全 数据合规

文献解读-肿瘤测序-第二十七期|《敲减通过控制TOP2A下调的NUSAP1可以抑制人胶质母细胞瘤的细胞增殖和侵袭》

INSVAST

基因测序 基因数据分析 生信服务 肿瘤测序

SRE是新一代ITIL的革新者

雅菲奥朗

SRE ITIL SRE培训 SRE考试 SRE认证

IoTDB组件AI Node发布9个月,如何使用你了解了吗?

Apache IoTDB

高并发场景下的库存管理,理论与实战能否兼得?

京东科技开发者

最新进展!Intel 18A产品,成功点亮!

E科讯

逻辑数据平台,多源异构实时数据高效同步的新途径

Aloudata

Data Fabric 数据编织 逻辑数据平台

ChatGPT 人工智能助理 Assistant

霍格沃兹测试开发学社

Supersonic 发行逻辑:从原型到爆款,健康增长循环助力开发者走向成功

极客天地

言犀智能体平台上线了!赶紧来试试!连接大模型与企业应用的“最后一公里”

京东科技开发者

堡垒机应用发布功能简单介绍-行云管家

行云管家

堡垒机 应用发布

低代码与软件定制开发的完美结合:生产管理软件的高效解决方案

天津汇柏科技有限公司

低代码 软件定制开发 生产管理软件

企业业务前端监控实践

京东科技开发者

观测云:零售业数据监控与分析的革新者

可观测技术

监控 零售

华为云全域Serverless技术创新:全球首创通用Serverless平台被ACM SIGCOMM录用

华为云开发者联盟

Serverless FunctionGraph 企业号 8 月 PK 榜 2024企业号8月pk 元戎

碳视野|加快构建碳排放双控制度体系工作方案

AMT企源

数字化转型 碳中和 双碳 碳管理 碳核算

Prometheus Exporter 在观测云中的应用与优势

可观测技术

#Prometheus

Mysql 锁:灵魂七拷问_文化 & 方法_柳树_InfoQ精选文章