【锁定直播】字节、华为云、阿里云等技术专家讨论如何将大模型接入 AIOps 解决实际问题,戳>>> 了解详情
写点什么

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:19658

评论

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

云图说丨华为云区块链引擎服务:高安全的区块链技术服务平台,轻松部署,快速上链

华为云开发者联盟

区块链 华为云 引擎 BCS

2022年企业直播行业发展洞察

易观分析

数据分析 报告 企业直播

大数据培训技术入门

小谷哥

TiDB升级与案例分享(TiDB v4.0.1 → v5.4.1)

TiDB 社区干货传送门

实践案例 版本升级 集群管理 管理与运维

【堡垒机小知识】硬件堡垒机是什么意思?其与云堡垒机有什么区别?

行云管家

云计算 网络安全 数据安全 堡垒机 云堡垒机

Alluxio为Presto赋能跨云的自助服务能力

Alluxio

数据架构 presto 跨云 Alluxio

共建共享数字世界的根:阿里云打造全面的云原生开源生态

阿里巴巴云原生

阿里云 容器 云原生 开源生态

多元宇宙:重塑新商业格局

智捷云

元宇宙 智捷云 智捷云科技

web前端培训好还是自学前端

小谷哥

即学即用的问题解决思维,给无意识的生活装上“后视镜”

图灵教育

CSDN TOP1“一个处女座的程序猿“如何通过写作成为百万粉丝博主

Lansonli

7月月更 如何写作

StarRocks 2.3 新版本特性介绍

StarRocks

LED透明屏和LED玻璃显示屏区别

Dylan

LED显示屏 户外LED显示屏 led显示屏厂家

QCon大会广州站它来了!独家定制双肩背包等你领取!

InfoQ写作社区官方

Qcon

TiCDC同步延迟问题处理

TiDB 社区干货传送门

实践案例 管理与运维 故障排查/诊断 大数据场景实践

TiFlash 源码阅读(五) DeltaTree 存储引擎设计及实现分析 - Part 2

TiDB 社区干货传送门

我和 TiDB 的故事 | TiDB 对我不离不弃,我亦如此

TiDB 社区干货传送门

人物访谈

新四化时代来袭,亚马逊云科技赋能汽车行业加速创新

Lily

推荐算法的三大研究热点

博文视点Broadview

详细讲解https证书openssl公钥私钥以及ssh公钥私钥的生成以及使用

Geek_6516e4

签约计划第三季

Dapr相比于SpringCloud和Istio的优势在哪?

王小凡

Java 程序员 istio SpringCloud 微服务框架

容器化 | 在 Rancher 中部署 MySQL 集群

RadonDB

MySQL 开源 容器化 rancher RadonDB

命里有时终须有--记与TiDB的一次次擦肩而过

TiDB 社区干货传送门

人物访谈 社区活动

我和 TiDB 的故事 | 缘份在,那就终是能相遇的

TiDB 社区干货传送门

人物访谈 社区活动

TiCDC迁移-TiDB到MySQL测试

TiDB 社区干货传送门

管理与运维

AI全流程开发难题破解之钥

华为云开发者联盟

人工智能 华为云

参加web前端培训入门学习

小谷哥

大数据培训机构应该注意什么

小谷哥

参加Java培训学习哪些方法

小谷哥

TiDB 操作实践 -- 备份与恢复

TiDB 社区干货传送门

备份 & 恢复

PD 源码分析- Checker: region 健康卫士

TiDB 社区干货传送门

TiKV 源码解读

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