MySQL锁概述

数据库锁是一种机制,用于管理并发访问数据库的方式。当多个用户或事务同时访问数据库时,可能会导致数据不一致或冲突的问题。数据库锁的作用是确保数据的一致性和完整性,同时允许多个用户并发地访问数据库。
需要注意的是,加锁是消耗资源的,锁的各种操作,包括获取锁、校验锁是否已解除、释放锁等,都会增加系统的开销。
这里以MySQL为例,介绍下数据库锁,关于数据库锁的理论知识可以参考数据库锁概述一文。

锁的分类

按照不同的划分标准,可以将锁分为多种类型。如悲观锁和乐观锁、共享锁和排他锁、意向锁、表锁和行锁和页锁等。

悲观锁和乐观锁

根据加锁的时机,可以将数据库锁可以分为两类:悲观锁和乐观锁。
所谓悲观锁,就是对数据的修改抱有悲观态度。当要对一个数据库中的一条数据进行修改时,为了避免同时被其他人修改,直接对该数据进行加锁以防止并发。这种借助数据库锁机制在修改数据之前先锁定,再修改的方式被称之为悲观并发控制(又名"悲观锁",Pessimistic Concurrency Control,简称"PCC")。
悲观锁采用的是"先取锁再访问"的保守策略,为数据处理的安全提供了保证。但是在效率方面,处理锁的机制会让数据库产生额外的开销,还有增加产生死锁的机会;另外,还会降低并行性,一个事务如果锁定了某行数据,其他事务就必须等待该事务处理完才可以处理那行数据。
所谓乐观锁,是相对悲观锁而言的,对数据的修改持有乐观的态度。当要对一个数据库中的一条数据进行修改时,假设数据一般不会造成冲突,只在数据进行提交的时候,对数据进行冲突检测,如果没有冲突,则直接修改,如果存在冲突则提供补偿策略,如执行回滚操作或执行重试操作。这次推迟并发冲突校验的方式被称为乐观并发控制(又名"乐观锁",Optimistic Concurrency Control,简称"OCC")。
乐观锁采用的是"推迟冲突校验"的积极策略,在数据争用不大、冲突较少的场景下中,可以获得更高的吞吐量,且不会引入锁,更不会带来死锁的问题。但是,对于数据争用较大,冲突较多的场景,乐观锁则会因补偿策略,带来回滚压力或CPU消耗。

共享锁和排他锁

根据是否独占数据还是共享数据,可以将数据库的锁分为共享锁和排他锁。
共享锁(shared lock,记为S),也称读锁,如果事务 T T T获得了数据项Q上的共享型锁,则 T T T对数据项Q可读但不可写,其他事务也可对数据项Q加共享锁,但不能加排他锁。
排他锁(exclusive lock,记为X),也称写锁,如果事务 T T T获得了数据项Q上的排他型锁,则 T T T对数据项Q即可写又可读,其他事务对数据项Q不能加任何锁。
共享锁和排他锁的兼容关系如下:

锁的类型共享锁(S)排他锁(X)
共享锁(S)兼容冲突
排他锁(X)冲突冲突

从上面的表格可知,共享锁和共享锁是兼容的,也就是说,如果事务 T T T对数据加了共享锁,那么其他事务是可以继续加共享锁的。但是,如果事务 T T T对数据加了排他锁,那么其他事务是不可加任何锁的。
从数据隔离性的角度来说,共享锁主要是为了支持并发的读取数据而出现的,读取数据时,不允许其他事务对当前数据进行修改操作,从而有效避免"不可重复读"的问题。排他锁主要是为了解决在修改数据时,不允许其他事务对当前数据进行修改和读取操作,从而可以有效避免"脏读"的问题。

意向锁

意向锁是一种表锁,用来表示一个事务接下来要获取的行锁类型(共享锁还是排他锁)。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.

当一个事务想要获取某行的锁时,它必须先获取该行所在表的意向锁。根据意图获取的行锁类型,可以将意向锁细分为意向共享锁(Intention Shared lock,IS)和意向排他锁(Intention eXclusive lock,IX)。意向共享锁表示该事务要获取的行锁类型是共享锁,而意向排他锁则表示该事务要获取的行锁类型是排他锁。
意向锁主要用于表锁和行锁共存的场景。举例来说,如果一个事务对表中的某一行加行锁,那么当另一个事务想对表加锁时,如果没有意向锁,则需要遍历该表的所有行,确保不存在锁冲突。如果有意向锁,如果可以兼容,则另一个事务进一步加锁,否则,直接返回,提示锁冲突。意向锁的兼容关系如下:

锁的类型共享锁(S)排他锁(X)意向共享锁(IS)意向排他锁(IX)
共享锁(S)兼容冲突兼容冲突
排他锁(X)冲突冲突冲突冲突
意向共享(IS)兼容冲突兼容兼容
意向排他锁(IX)冲突冲突兼容兼容

从上面的表格可知,意向锁之间是兼容的。也就是说,对同一个表,是可以随便加意向锁的。但是,对于意向共享锁来说,和共享锁是兼容的,和排他锁是冲突的。这主要是因为意向共享锁目的是给特定的行添加共享锁,而共享锁与排他锁是冲突的。同样的,对于意向排他锁来说,对共享锁或排他锁都是冲突的,这主要是因为意向排他锁目的是给特定的行添加排他锁,而排他锁与共享锁或排他锁是冲突的。
需要说明的是,对InnoDB来说,意向锁是由InnoDB执行引擎自己维护的,用户无法手动操作意向锁。当向数据行加共享锁/排他锁之前,InooDB 会自动先获取该数据行所在数据表的对应意向锁。
此外,除了存在意向共享锁和意向排他锁,还有共享排他型意向锁(shared and intention-exclusive, SIX),见于多粒度封锁协议中。有兴趣的同学可以自行学习。

表锁和行锁和页锁

根据加锁的粒度,可以将数据库的锁细分为表锁、行锁、页锁。
表锁(Table Lock)是一种粗粒度的锁,它锁定整个表,阻止其他事务访问表中的任何行。表锁适用于需要对整个表进行操作的情况,表锁开销小,且加锁快,但因锁的粒度较大,发生锁冲突的概率较高,数据库的并发性能较低。
行锁(Row Lock)是一种细粒度的锁,它锁定指定的行。行锁开销大,且加锁慢,但因其加锁粒度较小,发生锁冲突的概率较低,数据库的并发性能较高。
页锁(Page Lock)是介于行锁和表锁之间的一种锁机制,它锁定表的一个页或多个页。页锁通常在特定情况下使用,例如当需要批量操作数据时。页锁的开销和加锁速度也介于行锁和表锁之间,数据库的并发性能一般。注意,页级锁是 MySQL 中比较独特的一种锁定级别,在其他数据库中并不常见。页级锁主要应用于 BDB(BerkeleyDB )存储引擎中,这里不过多介绍,有兴趣的同学还请自行学习。
此外,无论是表锁,还是行锁,都可以根据是否独占数据还是共享数据,进一步细分为共享锁和排他锁。

锁的使用

对不同的存储引擎,锁的支持情况和使用方式是不同的。这里重点介绍下MyISAM和InnoDB两种存储引擎的锁的使用,其他引擎的锁的使用还请自行学习。

表锁的使用

MyISAM 只支持表级锁,不支持行锁。在执行 select,update,delete,insert 等语句都会给表自动加锁(针对读操作加共享锁、针对写操作加排他锁)。
InnoDB默认采用行锁,在未使用索引字段查询时升级为表锁。需要说明的是,即便在条件中使用了索引字段,MySQL会根据自身的执行计划,考虑是否使用索引。如果MySQL认为全表扫描效率更高,即使指定了索引字段,也不会使用索引,这种情况下InnoDB将使用表锁,而不是行锁。因此,在分析锁冲突时,有必要进一步检查SQL的执行计划,以确认是否真正使用了索引。注意,以下场景下,会优先使用表锁:
(1) 全表更新。事务需要更新大部分或全部数据,且表又比较大。若使用行锁,会导致事务执行效率低,从而可能造成其他事务长时间锁等待和更多的锁冲突。
(2) 多表查询。事务涉及多个表,比较复杂的关联查询,很可能引起死锁,造成大量事务回滚。这种情况若能一次性锁定事务涉及的表,从而可以避免死锁、减少数据库因事务回滚带来的开销。

行锁的使用

InnoDB为实现行锁,提供了多种实现方式。如记录锁(Record Lock)、间隙锁(Gap Lock)、临键锁(Next-Key Lock)等。需要说明的是,行锁仅在使用索引字段时才会生效,否则会升级为表锁。

记录锁(Record Lock)

记录锁是封锁记录,记录锁也叫行锁,示例如下:

SELECT * FROM `test_table` WHERE `id` = 1 FOR UPDATE;

它会在 id=1 的记录上加上记录锁,以阻止其他事务插入,更新,删除 id=1 这一行。

间隙锁(Gap Lock)

间隙锁,锁定一个范围,但不包含记录本身,间隙锁是封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。间隙锁主要目的,也是为了避免出现幻读(Phantom Read),对应的事务的隔离级别降级为可重复读。如果将事务的隔离性级别调整成读已提交或读未提交,间隙锁都会失效。间隙锁对应的事务隔离级别是可重复。示例如下:

SELECT * FROM `test_table` WHERE `id` > 100 FOR UPDATE

更多间隙锁的使用示例可以参考MySQL锁 —— 记录锁、间隙锁、临键锁、自增锁 一文。
以下情况均会产生间隙锁:
(1) 使用普通索引,且需要锁定一个区间。
(2) 使用多列唯一索引,且需要锁定一个区间。
(3) 使用唯一索引,且需要锁定一个区间。
注意,间隙锁封锁的不是多条记录,而是一个区间,以防止出现幻读现象。

临键锁(Next-Key Lock)

临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。同间隙锁一样,临键锁也是为了避免出现幻读(Phantom Read)。同样的,临键锁对应的事务隔离级别是可重复。示例如下:

SELECT * FROM table WHERE age <= 24 FOR UPDATE; 

更多临键锁的使用示例可以参考MySQL锁 —— 记录锁、间隙锁、临键锁、自增锁 一文。
临键锁会锁住一段左开右闭区间的数据。需要强调的一点是,InnoDB 中临键锁只与非唯一索引列有关,在唯一索引列(包括主键列)上不存在临键锁。

锁优化

MySQL锁机制是确保数据库数据一致性和完整性的关键技术,同时也是提高数据库性能的挑战之一。了解不同类型的锁以及它们的适用场景是设计高效数据库应用程序的重要一步。
在使用锁时,需要根据应用程序的需求选择合适的锁类型,同时考虑事务隔离级别以及优化策略,以提高并发性能并避免常见的锁问题。
为了优化MySQL锁性能,可以考虑以下几个策略:
(1) 选择合适的隔离级别
(2) 减小事务的规模
(3) 尽量在SQL中使用索引
(4) 避免长时间的锁定
(5) 定期清理无效的锁

参考

数据库系统概念 Abraham Silberschatz, Henry F. Korth, S. Sudarshan 著
https://www.cnblogs.com/qlqwjy/p/7798266.html 乐观锁和悲观锁的区别
https://www.cnblogs.com/kexinxin/p/11620345.html 数据库中的锁
https://cloud.tencent.com/developer/article/2332879 MySQL 锁的完全解析:提高数据库性能的关键技术
https://learnku.com/articles/39212 一张图彻底搞懂 MySQL 的锁机制
https://www.zhihu.com/tardis/zm/art/52312376?source_id=1005 数据库基础(三)Mysql里的锁
https://zhuanlan.zhihu.com/p/185003485 详解 MySql InnoDB 中意向锁的作用
https://dev.mysql.com/doc/refman/5.7/en/innodb-locking.html#innodb-intention-locks InnoDB Locking
https://blog.csdn.net/zcl_love_wx/article/details/82015281 一分钟深入Mysql的意向锁——《深究Mysql锁》
https://zhuanlan.zhihu.com/p/52879825 浅谈数据库共享锁与排它锁
https://juejin.cn/post/7088256473574309919 MySQL表锁、行锁和页锁
https://www.mysqlzh.com/doc/218.html BDB (BerkeleyDB)存储引擎
https://blog.csdn.net/kuyuyingzi/article/details/87710259 MySQL 表锁和行锁机制(很详细)
https://blog.csdn.net/qq_16268979/article/details/103441178 MyISAM的表锁和InnoDB的行锁
https://www.jianshu.com/p/478bc84a7721 MySQL记录锁、间隙锁、临键锁(Next-Key Locks)详解
https://blog.csdn.net/zhangchaoyang/article/details/108809249 MySQL锁 —— 记录锁、间隙锁、临键锁、自增锁

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

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

相关文章

ajax同步与异步,json-serve的安装与使用,node.js的下载

20.ajax json 轻量级的数据格式做配置文件网络传输 xml 重量级的数据格式 可扩展标记语言做配置文件网络传输 现在目前主流就是大量采用json做网络传输数据格式 1.ajax的概念: 与服务器进行’通信’的一种技术,能够实现异步的刷新页面 **同步:**按照顺序一步步的执行,容易造…

VMware和Debian下载

文章目录 ⭐️写在前面的话⭐️一、VMware二、Debain三、建立虚拟机&#x1f680; 先看后赞&#xff0c;养成习惯&#xff01;&#x1f680;&#x1f680; 先看后赞&#xff0c;养成习惯&#xff01;&#x1f680; ⭐️写在前面的话⭐️ CSDN主页&#xff1a;程序员好冰 目前在…

多输入多输出 | MATLAB实现CNN-GRU-Attention卷积神经网络-门控循环单元结合SE注意力机制的多输入多输出预测

多输入多输出 | MATLAB实现CNN-GRU-Attention卷积神经网络-门控循环单元结合SE注意力机制的多输入多输出预测 目录 多输入多输出 | MATLAB实现CNN-GRU-Attention卷积神经网络-门控循环单元结合SE注意力机制的多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果…

使用PyTorch处理多维特征输入的完美指南

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

C++ 模板同时使用默认参数和偏特化

C 模板同时使用默认参数和偏特化 正常的偏特化都很简单&#xff0c;但是如果和默认参数碰到一起就会复杂一点点 先讲答案&#xff08;按照顺序&#xff09;&#xff1a; 如果显示指定了&#xff0c;首先看显示指定的如果没显示指定&#xff0c;就找是否有默认参数的版本如果都…

Element Plus阻止 el-dropdown、el-switch等冒泡事件

最近做vue3项目&#xff0c;使用Element Plus,又遇到坑了&#xff01; 问题点&#xff1a;组件中遇到事件冒泡问题了&#xff0c;el-checkbox 中 change事件要求阻止冒泡&#xff0c;如下代码中要求点击checkbox时不调用li标签的show方法 <li click"show()">…

STM32物联网基于ZigBee智能家居控制系统

实践制作DIY- GC0169-ZigBee智能家居 一、功能说明&#xff1a; 基于STM32单片机设计-ZigBee智能家居 二、功能介绍&#xff1a; 1个主机显示板&#xff1a;STM32F103C最小系统ZigBee无线模块OLED显示器 语音识别模块多个按键ESP8266-WIFI模块&#xff08;仅WIFI版本有&…

Spring Cloud Pipelines 入门实践

文章目录 1. 前言2. Spring Cloud Pipelines 是做什么的2.1. 预定义的流程2.2. 集成测试和契约测试2.3.部署策略 4. Spring Cloud Pipelines的使用示例4.1. 创建一个Spring Boot应用4.2. 将代码托管到GitHub仓库4.3. 添加Spring Cloud Pipelines依赖4.4. 配置Spring Cloud Pipe…

生成Android证书

前提&#xff1a;确保本机安装好了java1.8 第一步 打开CMD keytool -genkey -alias AAAA -keyalg RSA -keysize 2048 -validity 36500 -keystore D:\mygitee\keyStore\szxApp.jksD:\mygitee\keyStore\szxApp.jks是证书要生成的位置 szxApp.jks 是证书名称 D:\mygitee\keySto…

volatile为什么无法保证原子性

假设定义 volatile int i 0; 现在2个线程同时 i&#xff0c;为什么数据还可能会出错&#xff1f;一起来看下图&#xff0c;虽然volatile的机制是&#xff1a;如果volatile修饰的变量有修改&#xff0c;那么会将变更内容写回主内存&#xff0c;同时让其他线程工作内存的该变量缓…

Pytorvh之Vision Transformer图像分类

文章目录 前言一、Transformer1.Transformer概览2.Self-Attention3.Multi-head Attention4.Position-wise Feed-Forward Networks(位置前馈网络)5.残差连接和层归一化6.Positional Encodings(位置编码) 二、Vision Transformer1.Vision Transformer概览2.Embedding层结构&#…

C++中resize和reserve

1.reserve(n)对capacity操作 capacity < n : 扩容capacity > n : 不操作 2.resize(n, m)对size操作 size < n : size增加到n 增加的值为msize > n : size减小到ncapacity < n : 先增大容量至n 再增大size至n 增加的值为m

计算机网络 | OSI 参考模型

计算机网络 | OSI 参考模型 计算机网络 | OSI 参考模型应用层表示层会话层传输层网络层数据链路层物理层 参考视频&#xff1a;王道计算机考研 计算机网络 参考书&#xff1a;《2022年计算机网络考研复习指导》 计算机网络 | OSI 参考模型 OSI 参考模型自下而上分为7层&…

Text-to-SQL小白入门(八)RLAIF论文:AI代替人类反馈的强化学习

学习RLAIF论文前&#xff0c;可以先学习一下基于人类反馈的强化学习RLHF&#xff0c;相关的微调方法&#xff08;比如强化学习系列RLHF、RRHF、RLTF、RRTF&#xff09;的论文、数据集、代码等汇总都可以参考GitHub项目&#xff1a;GitHub - eosphoros-ai/Awesome-Text2SQL: Cur…

mysql5.7获取json数组中的某个对象

前言 表中的一个字段类型是字符串&#xff0c;存的是一个对象数据。 现在要根据对象中的某个属性&#xff0c;获取到整个对象信息。 如果是mysql8&#xff0c;则可以使用JSON_TABLE。 示例&#xff1a;https://blog.csdn.net/weixin_44071721/article/details/123347229 sele…

MIT 6.S081 Operating System/Fall 2020 macOS搭建risc-v与xv6开发调试环境

文章目录 本机配置安装环境Homebrew执行安装脚本查看安装是否成功 RISC-V tools执行brew的安装脚本 QEMUXV6 测试有用的参考链接&#xff08;感谢前辈&#xff09;写在结尾 本机配置 电脑型号&#xff1a;Apple M2 Pro 2023 操作系统&#xff1a;macOS Ventura 13.4 所以我的电…

C# 处理TCP数据的类(服务端)

using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Threading;namespace TestDemo {/// <summary>/// 处理TCP数据的类&#xff08;服务端&#xff09;/// </summary>public class TcpService{/// <s…

Java中ArrayList 和 LinkedList 的区别是什么?

Java中ArrayList 和 LinkedList 的区别是什么&#xff1f; ArrayList 和 LinkedList 都是Java中常用的集合类&#xff0c;它们用于存储和操作元素的容器&#xff0c;但在内部实现和使用方式上有很大的区别。以下是它们的区别、作用、优缺点以及示例说明&#xff1a; 区别&…

Linux 安全 - LSM hook点

文章目录 一、LSM file system hooks1.1 LSM super_block hooks1.2 LSM file hooks1.3 LSM inode hooks 二、LSM Task hooks三、LSM IPC hooks四、LSM Network hooks五、LSM Module & System hooks 一、LSM file system hooks 在VFS&#xff08;虚拟文件系统&#xff09;层…

JVM第六讲:JVM 基础 - Java 内存模型引入

JVM 基础 - Java 内存模型引入 很多人都无法区分Java内存模型和JVM内存结构&#xff0c;以及Java内存模型与物理内存之间的关系。本文是JVM第六讲&#xff0c;从堆栈角度引入JMM&#xff0c;然后介绍JMM和物理内存之间的关系, 为后面JMM详解, JVM 内存结构详解, Java 对象模型详…