MySQL的共享锁和排他锁

锁定读 Locking Reads

有过编程语言并发学习经验的同学,应该都了解过读写锁的概念。读写锁主要是为了解决多读少写条件下,程序的并发性能问题。它的特点即是:如果一个线程持有了读锁,那么其他线程也是可以继续读取它锁定的数据,但是不能进行修改,即加写锁;如果一个线程持有了写锁,那么它会阻止任何其他线程的读取和修改。在数据库领域,也有读写锁的概念,下面让我们来了解一下。

在一个事务中,查询数据并且插入或者更新相关的数据,使用常规的 SELECT 语句并不能提供足够的保护。其他事务可以更新或者删除你刚好查询的数据行。因此,InnoDB 支持了两种不同类型的锁定读来提供额外的安全性。Locking Reads 这里我把它称为锁定读,它的作用就是在查询数据时加上读锁或者写锁。

  • 共享锁 Shared Lock,又称为读锁,简称 S 锁
    允许一个事务读取数据,但不允许其他事务修改数据。共享锁通常用于查询操作,以确保查询期间不会有事务修改数据。
  • 排他锁 Exclusive Lock,又称为写锁,简称 X 锁
    允许一个事务读取和修改数据,但不允许其他事务读取或者修改数据。排他锁通常用于更新或者删除操作,以确保在事务完成之前不会有其他事务修改数据。

注: 我觉得 Exclusive Lock 翻译成独占锁也挺好的。

共享锁和排他锁针对的是数据行级别的锁,而不是针对的整个表的锁。不过,在某些情况下,它也会从行锁退化成表锁(这是很严重的问题,应该极力避免它的发生)。

因此在一个事务中查询数据时,需要根据需要来使用共享锁或者排他锁:

  • 查询加共享锁:SELECT ... FOR SHARE
  • 查询加排他锁:SELECT ... FOR UPDATE

注意:锁定读必须在事务语句中才可以生效,或者关系事务的自动提交。

SELECT ... FOR SHARE

在一个事务中,给查询的数据行设置一个共享锁。在事务提交之前,其他的事务(或者会话)可以读取这些数据行,但是不能修改它们。如果这些数据行中的任何数据被其他事务修改了并且没有提交,你的加锁查询必须等待,直到其他事务结束,并且会获取到最新的值。

SELECT ... FOR SHARESELECT ... LOCK IN SHARE MODE 的替代,但是为了向后兼容后者依然可以使用,所以这两句是等价的。因为我这里使用的 MySQL 是 8.0 的版本,所以参考的文档也是 8.0 的。

SELECT ... FOR UPDATE

在一个事务中,给查询的数据行设置一个排他锁,对于搜索遇到的索引记录,它会锁定数据行和相关的索引项,这与使用 UPDATE 语句的效果是相同的。其他事务会被阻止更新(UPDATE)这些数据行、执行查询加共享锁(SELECT ... FOR SHARE)或者读取在某些隔离级别的数据。一致性读取(Consistent Read)会忽略在读取视图中存在的记录上设置在数据行上的任何锁定。(旧版本的记录行无法被锁定;它们是通过 undo logs 重建在记录的内存副本上的)。

注:后面这个一致性读取涉及另一个 MySQL 的重要特性:MVCC,多版本并发控制

所有通过 FOR SHAREFOR UPDATE 查询设置的锁,在事务被提交或者回滚时都会被释放。

注意:外部查询语句的锁定读不会锁定子查询语句,除非在子查询语句中也使用锁定读。下面是两个官方文档的例子:

这条语句不会锁定表 t2 中的行:

SELECT * FROM t1 WHERE c1 = (SELECT c1 FROM t2) FOR UPDATE;

如果要锁定表 t2 中的行,在子查询中使用锁定读语句:

SELECT * FROM t1 WHERE c1 = (SELECT c1 FROM t2 FOR UPDATE) FOR UPDATE;

实践

这里来分别实践一下加读锁和加写锁的场景,以及这个过程。

测试表结构:现在是有一个用户账户表(t_user_account),现在再添加一个用户信息表(t_user_info),它的 account_id 字段是用户账户表的主键。

CREATE table t_user_account(id INT NOT NULL AUTO_INCREMENT,name VARCHAR(20) NOT NULL,balance INT NOT NULL,PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;CREATE table t_user_info(id INT NOT NULL AUTO_INCREMENT,account_id INT NOT NULL,PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

查询加读锁

那么现在我需要给用户信息表添加一条记录,这样会有问题吗?这里显然是需要事务的,因为这是多条 SQL 语句了,但是这样就高枕无忧了吗?

在这里插入图片描述

在这里插入图片描述

如果在第一个事务执行查询之后,第二个事务把它查询的数据给删除了呢?这样就会失去参照完整性(referential integrity)了。所以,为了确保在第一个事务执行完成之前,它所依赖的数据不被修改,我们需要加读锁(当然可以加写锁了,但是加了写锁其他事务就无法读取了,影响系统的性能)。如下图,加了写锁之后,第二个事务尝试去删除对应的记录就会被卡住(默认的超时时间是 50s)。

在这里插入图片描述

查询加写锁

这里来模拟一个并发存取钱的场景:

事务 A:查询 id = 1 的用户的余额,然后模拟存 200。
事务 B:查询 id = 1 的用户的余额,然后模拟取 400。

如果这里不加写锁,那么我们来看一下可能出现的错误:

在这里插入图片描述

由于可重复读的原因,第二个事务读取的是它那个时间点数据的快照(MVCC),这样就会导致最终的金额是错误的,两个事务对同一个金额进行修改。也就是说,在第一个事务读取到金额之后,应该阻止其他的事务进行读取,在它执行结束后,才能允许其他事务操作。所以这里需要加写锁,下面是在事务开始之后加写锁之后的执行效果,最终的结果是正确的。这样 id = 1 的这行记录就会被锁住,其他事务是无法对其进行查询(加锁 SELECT)和修改(UPDATE、DELETE)。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/111245.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CANOCO5.0实现冗余分析(RDA)最详细步骤

在地理及生态领域会常使用RDA分析,RDA的实现路径也有很多,今天介绍一下CANOCO软件的实现方法。 1.软件安装 时间调整到2010年 2.数据处理 得有不同的物种或者样点数值,再加上环境因子数据。 3.软件运行 4.结果解读 结果解读主要把握这几点…

Pytorch-以数字识别更好地入门深度学习

目录 一、数据介绍 二、下载数据 三、可视化数据 四、模型构建 五、模型训练 六、模型预测 一、数据介绍 MNIST数据集是深度学习入门的经典案例,因为它具有以下优点: 1. 数据量小,计算速度快。MNIST数据集包含60000个训练样本和1000…

【复杂网络建模】——ER网络和SF网络的阈值分析

目录 1、介绍ER网络和SF网络 2、计算网络阈值 2.1 ER(Erdős-Rnyi)网络 2.2 SF(Scale-Free)网络 3、 研究网络阈值的意义 1、介绍ER网络和SF网络 在复杂网络理论中,ER网络(Erdős-Rnyi网络&#xff…

mybatis:动态sql【2】+转义符+缓存

目录 一、动态sql 1.set、if 2.foreach 二、转义符 三、缓存cache 1. 一级缓存 2. 二级缓存 一、动态sql 1.set、if 在update语句中使用set标签&#xff0c;动态更新set后的sql语句&#xff0c;&#xff0c;if作为判断条件。 <update id"updateStuent" pa…

【USRP】集成化仪器系列3 :频谱仪,基于labview实现

USRP 频谱仪 1、设备IP地址&#xff1a;默认为192.168.10.2&#xff0c;请勿 修改&#xff0c;运行阶段无法修改。 2、天线输出端口是TX1&#xff0c;请勿修改。 3、通道&#xff1a;0 对应RF A、1 对应 RF B&#xff0c;运行 阶段无法修改。 4、中心频率&#xff1a;当需要…

Unity 结构少继承多组合

为什么不推荐使用继承&#xff1f; 继承是面向对象的四大特性之一&#xff0c;用来表示类之间的 is-a 关系&#xff0c;可以解决代码复用的问题。虽然继承有诸多作用&#xff0c;但继承层次过深、过复杂&#xff0c;也会影响到代码的可维护性。所以&#xff0c;对于是否应该在…

程序员为什么要写bug,不能一次性写好吗?

仅仅听到“Bug”这个词就会让你作为一个开发人员感到畏缩。我们相信&#xff0c;优秀的程序员是那些编写无错误代码的人。随着一些开发人员强调要成为一名零错误程序员&#xff0c;我们进行了更深刻的思考&#xff0c;并发现事实的准确性。 所有制作的软件都应该没有错误。对此…

强化学习笔记

马尔科夫决策过程 markov chain&#xff1a; S \mathcal{S} S MRP&#xff1a; S &#xff0c; R \mathcal{S&#xff0c;R} S&#xff0c;R MDP&#xff1a; S &#xff0c; A ( s ) &#xff0c; R &#xff0c; P \mathcal{S&#xff0c;A(s)&#xff0c;R&#xff0c;P} …

在 Redis 中处理键值 | Navicat

Redis 是一个键值存储系统&#xff0c;允许我们将值与键相关联起来。与关系型数据库不同的是&#xff0c; 在Redis 中&#xff0c;不需要使用数据操作语言 &#xff08;DML&#xff09; 和查询语法&#xff0c;那么我们如何进行数据的写入、读取、更新和删除操作呢&#xff1f;…

怎么检测UI卡顿?(线上及线下)

什么是UI卡顿&#xff1f; 在Android系统中&#xff0c;我们知道UI线程负责我们所有视图的布局&#xff0c;渲染工作&#xff0c;UI在更新期间&#xff0c;如果UI线程的执行时间超过16ms&#xff0c;则会产生丢帧的现象&#xff0c;而大量的丢帧就会造成卡顿&#xff0c;影响用…

prometheus + grafana进行服务器资源监控

在性能测试中&#xff0c;服务器资源是值得关注一项内容&#xff0c;目前&#xff0c;市面上已经有很多的服务器资 源监控方法和各种不同的监控工具&#xff0c;方便在各个项目中使用。 但是&#xff0c;在性能测试中&#xff0c;究竟哪些指标值得被关注呢&#xff1f; 监控有…

springcloud-gateway简述

Spring Cloud Gateway 是一个用于构建 API 网关的项目&#xff0c;它是 Spring Cloud 生态系统中的一部分&#xff0c;旨在为微服务架构提供动态路由、负载均衡、安全性和监控等功能。 网关工程对应pom文件 <?xml version"1.0" encoding"UTF-8"?>…

【ag-grid-vue】基本使用

ag-grid是一款功能和性能强大外观漂亮的表格插件&#xff0c;ag-grid几乎能满足你对数据表格所有需求。固定列、拖动列大小和位置、多表头、自定义排序等等各种常用又必不可少功能。关于收费的问题&#xff0c;绝大部分应用用免费的社区版就够了&#xff0c;ag-grid-community社…

在线设计APP ui的网站,分享这7款

在数字时代&#xff0c;用户界面&#xff08;UI&#xff09;设计变得非常重要&#xff0c;因为良好的UI设计可以改善用户体验&#xff0c;增强产品吸引力。随着科学技术的发展&#xff0c;越来越多的应用在线设计网站出现&#xff0c;为设计师和团队提供了一种新的创作方式。本…

【大数据知识】大数据平台和数据中台的定义、区别以及联系

数据行业有太多数据名词&#xff0c;例如大数据、大数据平台、数据中台、数据仓库等等。但大家很容易混淆&#xff0c;也很容易产生疑问&#xff0c;今天我们就来简单聊聊大数据平台和数据中台的定义、区别以及联系。 大数据平台和数据中台的定义 大数据平台&#xff1a;一个…

阿里云大数据实战记录8:拆开 json 的每一个元素,一行一个

目录 一、前言二、目标介绍三、使用 pgsql 实现3.1 拆分 content 字段3.2 拆分 level 字段3.3 拼接两个拆分结果 四、使用 ODPS SQL 实现4.1 拆分 content 字段4.2 拆分 level 字段4.3 合并拆分 五、使用 MySQL 实现六、总结 一、前言 商业场景中&#xff0c;经常会出现新的业…

JUC并发编程--------基础篇

一、多线程的相关知识 栈与栈帧 我们都知道 JVM 中由堆、栈、方法区所组成&#xff0c;其中栈内存是给谁用的呢&#xff1f;其实就是线程&#xff0c;每个线程启动后&#xff0c;虚拟 机就会为其分配一块栈内存。 每个栈由多个栈帧&#xff08;Frame&#xff09;组成&#xf…

极智嘉(Geek+)再获重磅荣誉,持续力领跑智慧物流行业发展

近日&#xff0c;全球仓储机器人引领者极智嘉(Geek)再度传来好消息&#xff0c;凭借着全球化的专业服务能力和稳健增长的亮眼海外成绩&#xff0c;一举荣登“2023出海品牌服务商”价值榜&#xff0c;成为唯一登榜的物流机器人企业。 作为率先出海的物流机器人企业&#xff0c…

博客系统后端(项目系列2)

目录 前言 &#xff1a; 1.准备工作 1.1创建项目 1.2引入依赖 1.3创建必要的目录 2.数据库设计 2.1博客数据 2.2用户数据 3.封装数据库 3.1封装数据库的连接操作 3.2创建两个表对应的实体类 3.3封装一些必要的增删改查操作 4.前后端交互逻辑的实现 4.1博客列表页 …