当前位置: 首页 > news >正文

MySQL锁(二) 共享锁与互斥锁

共享锁与排他锁

2.1 共享锁(S锁)

定义:一个事务已获取共享锁,当另一个事务尝试对具备共享锁的数据进行读操作时,可正常读;进行写操作时,会被共享锁排斥

共享锁的意思很简单,也就是不同事务之间不会排斥,可以同时获取锁并执行。但这里所谓的不会排斥,仅仅只是指不会排斥其他事务来读数据,但其他事务尝试写数据时,就会出现排斥性,举个例子理解:

事务 T1ID=18 的数据加了一个共享锁,此时事务 T2、T3 也来读取 ID=18 的这条数据,这时 T2、T3 是可以获取共享锁执行的;但此刻又来了一个事务T4,它则是想对 ID=18 的这条数据执行修改操作,此时共享锁会出现排斥行为,不允许 T4 获取锁执行。

MySQL 中,我们可以在SQL语句后加上相关的关键字来使用共享锁,语法如下:

SELECT ... LOCK IN SHARE MODE;
-- MySQL8.0之后也优化了写法,如下:
SELECT ... FOR SHARE;

这种通过在 SQL 后添加关键字的加锁形式,被称为显式锁,而实际上为数据库设置了不同的事务隔离级别后,MySQL 也会对 SQL 自动加锁,这种形式则被称之为隐式锁。

样例:做个关于共享锁的小测试,先打开两个cmd窗口并于 MySQL 建立连接

-- 窗口1:
-- 开启一个事务
begin;
-- 获取共享锁并查询 id=2 的数据
select * from bank_balance where id=2 lock in share mode;
-- 窗口2:
-- 开启一个事务
begin;
-- 获取共享锁并查询 id=2 的数据
select * from bank_balance where id=2 lock in share mode;-- 尝试修改id=2的数据
update bank_balance set balance=230 where id=2;

  • 当窗口1获取了共享锁,窗口2执行查询/读操作时 可获取共享锁、正常读;但当窗口2执行修改/写操作时 窗口2没反应、未执行成功。
  • 而当窗口1中事务A提交后,窗口2事务B的写操作才能继续往下执行。

由上可见,一个事务已获取共享锁,当另一个事务尝试对具备共享锁的数据进行读操作时,可正常读;进行写操作时,会被共享锁排斥。因此从这个实验中可以得知:共享锁也具备排他性,会排斥其他尝试写的线程,当有线程尝试修改同一数据时会陷入阻塞,直至持有共享锁的事务结束才能继续执行

2.2 排他锁(X锁)

上面简单的了解了共享锁之后,紧着来看看排他锁,排他锁也被称之为独占锁。

当一个线程获取到独占锁后,会排斥其他线程(进行读写操作),如若其他线程也想对共享资源/同一数据进行操作,必须等到当前线程释放锁并竞争到锁资源才行

值得注意的一点是:排他锁并不是只能用于写操作,对于一个读操作,咱们也可以手动地指定为获取排他锁,当一个事务在读数据时,获取了排他锁,那当其他事务来读、写同一数据时,都会被排斥。比如事务T1ID=18的这条数据加了一个排他锁,此时T2来加排他锁读取这条数据,T3来修改这条数据,都会被T1排斥。

MySQL中,可以通过如下方式显式获取独占锁:

SELECT ... FOR UPTATE;

测试:

当两个事务同时获取排他锁,尝试读取一条相同的数据时,其中一个事务就会陷入阻塞,直至另一个事务结束才能继续往下执行;

但是select * from bank_balance where id=2这种普通读 不会被阻塞,也就是另一个事务不获取排他锁读数据,而是以普通的方式读数据,这种方式则可以立刻执行,Why?是因为读操作默认加共享锁吗?并不是,因为你尝试加共享锁读这条数据时依旧会被排斥。

可以明显看到,第二个事务中尝试通过加共享锁的方式读取这条数据,依旧会陷入阻塞状态,那前面究竟是因为啥原因才导致的能读到数据呢?其实这跟另一种并发控制技术有关,即MVCC机制,详情可见 MVCC 原理分析、MySQL是如何解决幻读的。

增、删、改都会对数据添加X锁,在查询语句中使用for update也会添加X锁

S锁X锁
S锁×
X所××

2.3 MySQL锁的释放

在前面的测试中,每次都仅获取了锁,但好像从未释放过锁?其实MySQL中释放锁的动作都是隐式的,毕竟如果交给咱们来释放,很容易由于操作不当造成死锁问题发生。因此对于锁的释放工作,MySQL自己来干,就类似于JVM中的GC机制一样,把内存释放的工作留给了自己完成。

  • 但对于锁的释放时机,在不同的隔离级别中也并不相同,比如在“读未提交”级别中,是SQL执行完成后就立马释放锁;而在“可重复读”级别中,是在事务结束后才会释放。

如果完全按照数据库规范来实现RC隔离级别,为了保证其他事务可以读到未提交的数据,那就必须得在SQL执行完成后,立马释放掉锁,这时另一个事务才能读到SQL对应写的数据,但在InnoDB引擎中,它基于MVCC机制实现了该效果,为此,InnoDBRC级别中,SQL执行结束后并不会释放锁。

http://www.lryc.cn/news/594191.html

相关文章:

  • pages.json页面路由中,globalStyle的各个属性
  • 两个数据表的故事:第 1 部分
  • 测试中的bug
  • LVS-----TUN模式配置
  • 20250720-6-Kubernetes 调度-nodeName字段,DaemonS_笔记
  • Pinia 核心知识详解:Vue3 新一代状态管理指南
  • spring-cloud使用
  • 【数据结构】揭秘二叉树与堆--用C语言实现堆
  • 数据结构-线性表顺序表示
  • PrimeTime:高级片上变化(AOCV)
  • 小红书 MCP 服务器
  • Vue 3中reactive、ref、watchEffect和watch的底层原理及核心区别解析
  • SQL189 牛客直播各科目同时在线人数
  • SQL 调优第一步:EXPLAIN 关键字全解析
  • [Java恶补day44] 整理模板·考点七【二叉树】
  • Docker Desktop 入门教程(Windows macOS)
  • HTTP 进化史:从 1.0 到 3.0
  • The FastMCP Client
  • 你的created_time字段,用DATETIME还是TIMESTAMP?
  • Python自动化测试项目实战
  • Python 模块与包导入 基础讲解
  • Haproxy算法精简化理解及企业级高功能实战
  • 如何在看板中体现任务依赖关系
  • Windows CMD(命令提示符)中最常用的命令汇总和实战示例
  • 让黑窗口变彩色:C++控制台颜色修改指南
  • 30天打牢数模基础-SVM讲解
  • Linux操作系统从入门到实战(十一)回车换行问题与用户缓冲区问题
  • 内网后渗透攻击过程(实验环境)--3、横向攻击
  • dify创建OCR工作流
  • java抗疫物质管理系统设计和实现