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锁 —— 记录锁、间隙锁、临键锁、自增锁
相关文章:
MySQL锁概述
数据库锁是一种机制,用于管理并发访问数据库的方式。当多个用户或事务同时访问数据库时,可能会导致数据不一致或冲突的问题。数据库锁的作用是确保数据的一致性和完整性,同时允许多个用户并发地访问数据库。 需要注意的是,加锁是消…...

【Ceph Block Device】块设备挂载使用
文章目录 前言创建pool创建user创建image列出image检索image信息调整image大小增加image大小减少image大小 删除image从pool中删除image从pool中“延迟删除”image从pool中移除“延迟删除的image” 恢复image恢复指定pool中延迟删除的image恢复并重命名image 映射块设备格式化i…...

Arbitrum Stylus 的工作原理
理解 Arbitrum 如何协调 EVM 和 WASM 的共存是至关重要的。这不仅仅是拥有两个独立的引擎;这是一种增强两者优势的协同关系。 Arbitrum 的独特架构允许 EVM 和 WASM 之间进行无缝和同步的操作,这要归功于其统一的状态、跨 VM 调用和兼容的经济模型。 用…...

nextjs构建服务端渲染,同时使用Material UI进行项目配置
一、创建一个next项目 使用create-next-app来启动一个新的Next.js应用,它会自动为你设置好一切 运行命令: npx create-next-applatest 执行结果如下: 启动项目: pnpm dev 执行结果: 启动成功! 二、安装Mater…...
Java 使用 Easyexcel 导出大量数据
读Excel | Easy Excel 1、 我遇到的数据量超级大,使用传统的POI方式来完成导入导出很明显会内存溢出,并且效率会非常低;2、 数据量大直接使用select * from tableName肯定不行,一下子查出来300w条数据肯定会很慢;3、 …...

高效防汛决策:山海鲸可视化系统助力城市防洪
随着全球气候的变化,自然灾害如洪水、台风等频发,防范洪水成为城市管理者和居民们亟待解决的重要问题。 洪水的威胁 洪水是自然界的杀手之一,不仅会造成大量的财产损失,还可能危害人们的生命安全。因此,预测、监测和有…...

易点云CFO向征:CFO不能只讲故事,价值创造才是核心
作者 | 曾响铃 文 | 响铃说 在今年6月初,也是易点云上市6天后,《巴伦周刊》正式启动评价“2023港美上市中国企业CFO精英100”的活动。 时间来到9月,评价揭秘,易点云CFO向征成功入选,被评为“年度最具成长潜力CFO”…...

【计算机网络】poll | epoll
文章目录 1. pollpoll函数参数解析代码解析PollServer代码 poll 特点 2. epoll认识接口epoll_createepoll_ctlepoll_wait 基本原理红黑树就绪队列 1. poll poll函数参数解析 输入 man poll poll的第一个参数是文件描述符 poll的第二个参数为 等待的多个文件描述符(fd)数字层面…...

C++设计模式_07_Bridge 桥模式
文章目录 1. 动机(Motivation)2. 代码演示Bridge 桥模式2.1 基于继承的常规思维处理2.2 基于组合关系的重构优化2.3 采用Bridge 桥模式的实现 3. 模式定义4. 结构(Structure)5. 要点总结 与上篇介绍的Decorator 装饰模式一样&…...
[JAVA版本] Websocket获取B站直播弹幕——基于直播开放平台
教程 B站直播间弹幕Websocket获取 — 哔哩哔哩直播开放平台 基于B站直播开放平台开放且未上架时,只能个人使用。 代码实现 1、相关依赖 fastjson2用于解析JSON字符串,可自行替换成别的框架。 hutool-core用于解压zip数据,可自行替换成别的…...

第一个 Python 程序
三、第一个 Python 程序 好了,说了那么多,现在我们可以来写一下第一个 Python 程序了。 一开始写 Python 程序,个人不太建议用专门的工具来写,不方便熟悉语法,所以这里我先用 Sublime Text 来写,后期可以…...

广告牌安全监测,保障户外广告牌的安全与稳定
随着城市的发展和现代化,广告牌已经成为城市风景的一部分。然而,随之而来的是广告牌安全问题,因为它们暴露在各种天气和环境条件下,一旦掉落,可能对人们的生命和财产造成威胁。广告牌安全监测有效的解决了这一问题&…...

分类预测 | MATLAB实现KOA-CNN-GRU开普勒算法优化卷积门控循环单元数据分类预测
分类预测 | MATLAB实现KOA-CNN-GRU开普勒算法优化卷积门控循环单元数据分类预测 目录 分类预测 | MATLAB实现KOA-CNN-GRU开普勒算法优化卷积门控循环单元数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现KOA-CNN-GRU开普勒算法优化卷积门控循环单…...

进来了解实现官网搜索引擎的三种方法
做网站的目的是对自己的品牌进行推广,让越来越多的人知道自己的产品,但是如果只是做了一个网站放着,然后等着生意找上门来那是不可能的。在当今数字时代,实现官网搜索引擎对于提升用户体验和推动整体性能至关重要。搜索引擎可以帮…...

OpenCV3-Python(7)模板匹配和霍夫检测
模板匹配 膜版匹配不能匹配尺度变换和视角变换的图像 图片中查找和模板相似度最高的图像 计算相似程度最高的位置 res cv.matchTemplate(img , template, method) 该方法返回一个类似灰度图的东西,如果用的相关匹配,那么亮的地方就是可能匹配上的地方 …...

[C++11]花括号{}、initializer_list、auto、decltype
文章目录 1.花括号{ }的扩展2.initializer_list3.auto4.decltype5.容器的增加5.1array[useless]5.2forward_list[useless]5.3unordered_map/unordered_set5.4统一增加 6.知乎文章 1.花括号{ }的扩展 int main() {//C98花括号{ }支持 1.数组 2.结构体struct Point{int _x;int _…...

在Android平板上使用code-server公网远程Ubuntu服务器编程
文章目录 1.ubuntu本地安装code-server2. 安装cpolar内网穿透3. 创建隧道映射本地端口4. 安卓平板测试访问5.固定域名公网地址6.结语 1.ubuntu本地安装code-server 准备一台虚拟机,Ubuntu或者centos都可以,这里以VMwhere ubuntu系统为例 下载code server服务,浏览器…...
宝塔上安装mysql版本比较和区别
在宝塔上安装MySQL时,几个主要版本之间的区别主要在于性能、功能和安全性。 MySQL Community Server(社区版本):这是MySQL的开源免费版本,由社区支持,但不提供官方技术支持。这个版本对一般用户来说可能有…...

uniapp微信小程序自定义封装分段器。
uniapp微信小程序自定义封装分段器。 话不多说先上效果 这里我用的是cil框架 vue3 下面贴代码 组价代码: <template><view class"page"><viewv-for"(item, index) in navList":key"index"click"changeNav(ind…...

文心一言 VS 讯飞星火 VS chatgpt (111)-- 算法导论10.2 2题
二、用go语言,用一个单链表 L实现一个栈。要求操作 PUSH和 POP 的运行时间仍为 O(1)。 文心一言: 在 Go 语言中,我们可以用结构体来实现一个单链表,然后再用栈的相关操作。 以下是一个可能的实现方式: package mai…...

Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
Python爬虫(二):爬虫完整流程
爬虫完整流程详解(7大核心步骤实战技巧) 一、爬虫完整工作流程 以下是爬虫开发的完整流程,我将结合具体技术点和实战经验展开说明: 1. 目标分析与前期准备 网站技术分析: 使用浏览器开发者工具(F12&…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

基于 TAPD 进行项目管理
起因 自己写了个小工具,仓库用的Github。之前在用markdown进行需求管理,现在随着功能的增加,感觉有点难以管理了,所以用TAPD这个工具进行需求、Bug管理。 操作流程 注册 TAPD,需要提供一个企业名新建一个项目&#…...
iOS性能调优实战:借助克魔(KeyMob)与常用工具深度洞察App瓶颈
在日常iOS开发过程中,性能问题往往是最令人头疼的一类Bug。尤其是在App上线前的压测阶段或是处理用户反馈的高发期,开发者往往需要面对卡顿、崩溃、能耗异常、日志混乱等一系列问题。这些问题表面上看似偶发,但背后往往隐藏着系统资源调度不当…...
【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权
摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题:安全。文章将详细阐述认证(Authentication) 与授权(Authorization的核心概念,对比传统 Session-Cookie 与现代 JWT(JS…...

macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...

云原生时代的系统设计:架构转型的战略支点
📝个人主页🌹:一ge科研小菜鸡-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、云原生的崛起:技术趋势与现实需求的交汇 随着企业业务的互联网化、全球化、智能化持续加深,传统的 I…...