mysql全局锁表锁行锁全面操作实践

1.引言

锁我们都不陌生,在实际应用中,锁是解决并发问题的常用方案。可以说有资源共享,就会有竞争,有竞争就会需要锁。自然数据库作为存储层的解决方案,免不了数据共享,数据竞争,因此数据库中需要锁。

那么你知道,在mysql数据库中,都有哪些锁吗?今天我们就来说道说道mysql数据库中的锁,它们是

  • 全局锁
  • 表级锁
  • 行锁

2.案例

2.1.全局锁

全局锁的意思是,锁住整个数据库,就是这么霸气,锁住整个数据库!在mysql中,全局说,即是FTWRL(flush tables with read lock)。

很多时候,对于一个知识点,我们更关注的是在什么应用场景下需要它。对于全局锁来说,通常会应用在做逻辑备份的时候

  • 试想有一个数据库bank,其中有两张表a、表b
  • 我们需要将数据库bank的数据逻辑备份出来,如何保障备份前后的数据一致呢?
  • 即是说在备份过程中,不能再对bank数据库有更新的操作,可以读,但是不能更新,否则备份出来的数据,与原库数据会存在不一致

这个时候,全局锁FTWRL默默的站了起来,说:我来!那么全局锁,它其实做了三件事情

  • 上全局读锁
  • 清空表缓存
  • 上全局commit锁

下面我们通过一个示例演示一下,我的演示场景如下

ini 复制代码
#1.数据库bank,有一张表:account_info
#2.开启会话线程 a,执行命令:flush tables with read lock; 加全局读锁
#3.开启另一个会话线程 b,查询表account_info数据,预期执行成功
    sql:select * from account_info;
#4.开启另外一个会话线程 c,更新表account_info,预期执行阻塞
    sql:update account_info set account_no=1 where id=1;
#5.在会话线程a,执行命令:unlock tables; 释放锁
#6.观察会话线程c,更新解除阻塞,继续执行

图一:

图二:

2.2.表级锁

全局锁范围太大,会锁住整个数据库。表级锁的意思是说,锁的范围小一些,我不那么霸道,我只锁住某一个表。

表级锁有两种,一个是我们可以自主控制的表锁;另外一个是由数据库自动控制的MDL(meta data lock)元数据锁

我们先来看MDL锁,稍后再通过示例演示自主控制锁。元数据锁它是指在对某个表a执行增删改查dml操作的时候,mysql数据库会给表a加上MDL读锁;在对表a执行ddl操作的时候,比如增加一个字段,mysql数据库会给表a加上MDL写锁。

你需要注意的是读锁之间不互斥,因此表a上的dml操作支持并发执行;读锁与写锁,写锁与写锁之间互斥,因此表a上的dml操作,与ddl操作之间是不能并发执行的,会发生阻塞

MDL锁终归不由我们控制,暂时放下它,我们接下来通过示例演示显示控制表级锁,演示场景如下

csharp 复制代码
#1.数据库bank,有一张表:account_info
#2.开启会话线程 a,执行命令:lock tables account_info read;加锁
#3.开启会话线程 b,查询表account_info数据,预期正常执行
    sql:select * from account_info;
#4.开启会话线程 c,更新表account_info数据,预期被阻塞
    sql:update account_info set account_no=1 where id=1;
#5.会话线程 a,执行命令:unlock tables;释放锁
#6.观察会话线程 c,锁解除,更新操作继续执行

图一:

图二:

另外显示给表加锁,除了可以加读锁,还可以加写锁,命令是这样

arduino 复制代码
#1.写锁:lock tables account_info write;

命令上加读锁,写锁差异不大,只是将read改成write。但是你需要注意读锁不互斥读操作,写锁互斥一切操作。这里我就不演示了,如果你感兴趣,我建议你亲自实践一下。

2.3.行锁

上面我们看完了全局锁,和表锁,它们都是在server层实现的,且从锁范围来说都比较粗,这不利于系统并发性能的提升。

那么事实上在mysql数据库中,还有行锁的存在,单从字面意思就能理解,行锁即是对行进行加锁,锁的范围更小了,更有利于系统的并发能力提升。但是你需要注意,行锁是在存储引擎层实现的,并不是所有的存储引擎都支持行锁,平常我们常用的存储引擎中,比如说Innodb支持行锁,而Myisam不支持行锁。这也是在实际应用中,会更加推荐使用Innodb的其中一个原因

另外关于行锁,你还需要知道一个事实,即两阶段锁提交协议什么意思呢?它是指行锁在需要的时候加锁,但并不是说sql执行完成就会释放锁,而是在sql语句所在的整个事务结束的时候释放锁,这就是两阶段锁提交协议

为什么需要知道两阶段锁提交协议?它对我们平常开发有什么帮助吗?我举一个例子你应该就明白了。比如说用户购物操作,业务执行顺序可能如下

bash 复制代码
--方案一
#1.选择商品
#2.加入购物车
#3.下订单
#4.支付
#5.扣减库存
​
--方案二
#1.选择商品
#2.加入购物车
#3.扣减库存
#4.下订单
#5.支付

如果是你来实现以上业务,你会选择方案一,还是方案二呢?我们试着分析一下,最有可能存在并发冲突的地方是【扣减库存】,因为商品库存是共享资源,用户A、用户B购买相同商品,扣减的是相同商品的库存。这个不难理解。

那么结合两阶段锁提交协议,锁是在需要的时候执行加锁,即执行扣减库存sql语句的时候加锁,但是要等到整个事务结束的时候才会释放锁,这里业务执行事务范围【1-5】。

如果要提升业务执行的并发度,就需要减少锁的时间,那么现在你应该知道了,方案一优于方案二,原因是方案一中,扣减库存在最后一步才会加锁,锁的时间最短。

当然,我这里是举的示例,在实际应用中,我们应该要结合业务特点来选择最终合适的方案,你一定要注意这一点,任何技术解决方案,最重要的一点都是要优先满足业务

另外你也看到了,我们知道一些底层实现原理,对与日常业务开发,其实是有很多帮助的,这也是我在所有分享文章中,最想要分享给你的地方:知其然,知其所以然!好了,关于锁我就暂时给你分享到这里了,期望给你带来一些收获!

相关推荐
杉之1 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
morris1311 小时前
【redis】redis实现分布式锁
数据库·redis·缓存·分布式锁
hycccccch2 小时前
Canal+RabbitMQ实现MySQL数据增量同步
java·数据库·后端·rabbitmq
bobz9652 小时前
k8s 怎么提供虚拟机更好
后端
这个懒人2 小时前
深入解析Translog机制:Elasticsearch的数据守护者
数据库·elasticsearch·nosql·translog
Yan-英杰3 小时前
【百日精通JAVA | SQL篇 | 第二篇】数据库操作
服务器·数据库·sql
bobz9653 小时前
nova compute 如何创建 ovs 端口
后端
用键盘当武器的秋刀鱼3 小时前
springBoot统一响应类型3.5.1版本
java·spring boot·后端
NineData3 小时前
NineData云原生智能数据管理平台新功能发布|2025年3月版
数据库
Asthenia04124 小时前
从迷宫到公式:为 NFA 构造正规式
后端