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】。

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

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

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

相关推荐
liliangcsdn1 小时前
如何使用python创建和维护sqlite3数据库
数据库·sqlite
QX_hao5 小时前
【Go】--map和struct数据类型
开发语言·后端·golang
MC丶科6 小时前
【SpringBoot 快速上手实战系列】5 分钟用 Spring Boot 搭建一个用户管理系统(含前后端分离)!新手也能一次跑通!
java·vue.js·spring boot·后端
G探险者6 小时前
为何一个系统上线要经过N轮测试?带你看懂企业级发布体系
后端
TDengine (老段)7 小时前
TDengine 数学函数 DEGRESS 用户手册
大数据·数据库·sql·物联网·时序数据库·iot·tdengine
TDengine (老段)7 小时前
TDengine 数学函数 GREATEST 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
安当加密8 小时前
云原生时代的数据库字段加密:在微服务与 Kubernetes 中实现合规与敏捷的统一
数据库·微服务·云原生
lang201509288 小时前
Spring Boot 入门:5分钟搭建Hello World
java·spring boot·后端
爱喝白开水a8 小时前
LangChain 基础系列之 Prompt 工程详解:从设计原理到实战模板_langchain prompt
开发语言·数据库·人工智能·python·langchain·prompt·知识图谱