MySQL-锁:共享锁(读)、排他锁(写)、表锁、行锁、意向锁、间隙锁,锁升级
MySQL-锁:共享锁(读)、排他锁(写)、表锁、行锁、意向锁、间隙锁
- 共享锁(读锁)、排他锁
- 表锁
- 行锁
- 意向锁
- 间隙锁
- 锁升级
MySQL数据库中的锁是控制并发访问的重要机制,它们确保数据的一致性和完整性。下面是MySQL数据库中常见的锁类型以及它们的特点和应用场景:
- 共享锁(Shared Lock):
- 特点:共享锁允许多个事务同时读取同一资源,但阻止其他事务获取排他锁,从而防止并发写入。
- 应用场景:适用于读取操作,例如
SELECT
语句。
- 排他锁(Exclusive Lock):
- 特点:排他锁阻塞其他事务的读锁和写锁,只允许一个事务对资源进行写操作,防止其他事务读取或写入资源。
- 应用场景:适用于写入或修改操作,例如
INSERT
、UPDATE
、DELETE
语句。
- 表锁(Table Lock):
- 特点:表锁会锁定整张表,阻塞其他事务对表的写操作,但不阻塞对表的读操作。
- 应用场景:适用于对整张表进行操作的场景,例如MyISAM存储引擎的表级锁。
- 行锁(Row Lock):
- 特点:行锁允许事务锁定表中的特定行,而不是整张表,提高并发性。但容易引发死锁。
- 应用场景:适用于需要精确控制行级别访问的场景,例如InnoDB存储引擎的行级锁。
- 意向锁(Intention Locks):
- 意向锁是一种表明事务将在某个级别上加锁的锁类型。意向锁有两种类型:意向共享锁和意向排他锁。它们用于表示一个事务打算在一个更高的层级上(如行级别或表级别)加锁。
- 意向锁是为了帮助数据库管理系统了解一个事务打算在哪个级别上进行锁定,以便避免死锁。
- 间隙锁(Gap Locks):
- 间隙锁是一种特殊类型的锁,用于防止其他事务将新的键插入到已有的索引范围中。间隙锁在某个范围的键之间创建了一个间隙,防止其他事务插入新的键。
- 间隙锁通常与范围查询操作一起使用,例如
SELECT ... WHERE ... BETWEEN ... AND ...
语句。
现在,让我们来看一个实际案例,说明MySQL中锁的应用:
假设有一个电子商务网站,多个用户同时访问产品库存信息,并尝试下单购买同一件商品,这时候可能会涉及到对产品库存的读写操作。
- 对于读取产品库存信息的操作,可以使用共享锁(读锁),允许多个用户同时读取产品库存信息,不会互相阻塞,保证并发性。
- 当某个用户下单购买商品时,需要更新产品库存信息,此时需要使用排他锁(写锁),阻止其他用户同时修改库存信息,确保数据的一致性。
如果没有使用合适的锁机制,可能会导致以下问题:
- 如果多个用户同时读取产品库存信息但不加锁,则可能读取到错误的库存数量。
- 如果多个用户同时尝试购买同一件商品而没有加锁,则可能导致超卖或者库存错误的问题。
共享锁(读锁)、排他锁
CREATE TABLE articles (article_id INT AUTO_INCREMENT PRIMARY KEY,title VARCHAR(255),content TEXT
);
事务1:查看博客文章内容(共享锁)
共享锁允许多个事务同时读取同一资源,但阻止其他事务获取排他锁,从而防止并发写入。
START TRANSACTION;
SELECT * FROM articles WHERE article_id = 123 LOCK IN SHARE MODE;
-- 读取文章内容
COMMIT;
事务2:可以编辑文章内容(排他锁)
排他锁阻塞其他事务的读锁和写锁,只允许一个事务对资源进行写操作,防止其他事务读取或写入资源
START TRANSACTION;
SELECT * FROM articles WHERE article_id = 123 FOR UPDATE;
-- 编辑文章内容
UPDATE articles SET content = 'New content' WHERE article_id = 123;
COMMIT;
表锁
假设有一个在线预订系统,有一个订单表,需要定期对订单表进行清理和维护操作
CREATE TABLE orders (order_id INT AUTO_INCREMENT PRIMARY KEY,customer_id INT,order_date DATETIME
);
-- 事务1:清理过期订单(表锁)
START TRANSACTION;
LOCK TABLES orders WRITE;
-- 清理过期订单
DELETE FROM orders WHERE order_date < DATE_SUB(NOW(), INTERVAL 30 DAY);
UNLOCK TABLES;
COMMIT;
行锁
假设有一个在线论坛系统,用户可以对帖子进行评论,需要确保在用户对同一篇帖子进行评论时不会产生冲突。
CREATE TABLE posts (post_id INT AUTO_INCREMENT PRIMARY KEY,title VARCHAR(255),content TEXT
);CREATE TABLE comments (comment_id INT AUTO_INCREMENT PRIMARY KEY,post_id INT,user_id INT,comment_text TEXT,
);
-- 事务1:添加评论(行锁)
START TRANSACTION;
SELECT * FROM posts WHERE post_id = 123 FOR UPDATE;
-- 添加评论
INSERT INTO comments (post_id, user_id, comment_text) VALUES (123, 456, 'Great post!');
COMMIT;
事务执行SELECT * FROM posts WHERE post_id = 123 FOR UPDATE;
语句获取了帖子ID为123的行级排他锁。这样做的目的是确保在添加评论之前,对于帖子ID为123的行数据,其他事务无法同时修改,以避免数据不一致或丢失的情况发生
意向锁
假设有一个在线购物系统,其中有两张表:orders
(订单表)和order_details
(订单详情表)。订单表记录了每个订单的基本信息,订单详情表则记录了每个订单中的具体商品信息。
CREATE TABLE orders (id INT AUTO_INCREMENT PRIMARY KEY,customer_id INT,order_date DATETIME
);CREATE TABLE order_details (id INT AUTO_INCREMENT PRIMARY KEY,order_id INT,product_id INT,quantity INT,
);
现在假设有一个事务需要向订单表中插入一条新的订单记录,并且需要向订单详情表中插入相关的商品信息。
START TRANSACTION;-- 获取意向排他锁,表明将在订单表上进行排他锁定
SELECT * FROM orders WHERE customer_id = 100 FOR UPDATE;-- 插入新的订单记录
INSERT INTO orders (customer_id, order_date) VALUES (100, NOW());
SET @last_order_id = LAST_INSERT_ID();-- 插入订单详情
INSERT INTO order_details (order_id, product_id, quantity) VALUES (@last_order_id, 1, 2);
INSERT INTO order_details (order_id, product_id, quantity) VALUES (@last_order_id, 2, 3);COMMIT;
初始:
执行事务后:
在这个例子中,事务首先获取了意向排他锁,以表明将在订单表上进行排他锁定。然后向订单表中插入了一条新的订单记录,并且通过获取LAST_INSERT_ID()
函数获取了刚插入的订单ID,接着向订单详情表中插入了相关的商品信息。
间隙锁
假设有一个产品表,其中的产品ID是一个唯一索引。现在有两个事务,一个事务需要检查某个特定的产品是否存在,而另一个事务需要向产品表中插入一个新的产品。
-- 事务1:检查产品是否存在
START TRANSACTION;
SELECT * FROM products WHERE product_id = 5 LOCK IN SHARE MODE;
-- 如果存在特定产品,则执行相应操作
COMMIT;-- 事务2:插入新的产品
START TRANSACTION;
-- 获取间隙锁,防止其他事务在该范围内插入新的产品
SELECT * FROM products WHERE product_id > 4 AND product_id < 6 FOR UPDATE;
-- 插入新的产品
INSERT INTO products (product_id, name, price) VALUES (5, 'New Product', 10.99);
COMMIT;
事务1:检查产品是否存在
START TRANSACTION;
SELECT * FROM products WHERE product_id = 5 LOCK IN SHARE MODE;
-- 如果存在特定产品,则执行相应操作
INSERT INTO products (product_id, name, price) VALUES (5, 'New Product', 23.11);
COMMIT;
无法插入
在这个事务中,我们使用LOCK IN SHARE MODE
语句获取了产品ID为5的共享锁,以确保其他事务可以同时读取相同的产品信息,但是不能进行写操作。
事务2:插入新的产品
START TRANSACTION;
-- 获取间隙锁,防止其他事务在该范围内插入新的产品
SELECT * FROM products WHERE product_id > 4 AND product_id < 6 FOR UPDATE;
-- 插入新的产品
INSERT INTO products (product_id, name, price) VALUES (5, 'New Product', 10.99);
COMMIT;
无法插入
在这个事务中,我们使用FOR UPDATE
语句获取了产品ID大于4且小于6的间隙锁,以防止其他事务在这个范围内插入新的产品。然后,我们向产品表中插入了一个新的产品。
锁升级
在MySQL中,锁升级是指事务在执行过程中,将当前持有的锁从低级别升级到更高级别的过程。这个过程通常是为了保证数据的完整性和一致性,同时尽量减少锁的持有时间,以提高并发性能。
MySQL中的锁升级有时是隐式的,有时需要显式操作。以下是一些锁升级的例子,以及相应的SQL语句:
CREATE TABLE products (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(255),category_id INT,price DECIMAL(10, 2),quantity INT
);CREATE TABLE orders (id INT AUTO_INCREMENT PRIMARY KEY,customer_id INT,product_id INT,quantity INT,order_date DATETIME,
);
-
从行级锁升级到表级锁:
例子:
START TRANSACTION; SELECT * FROM products WHERE category_id = 1 FOR UPDATE; -- 此时事务持有了行级锁-- 执行一些操作,需要将行级锁升级到表级锁 UPDATE products SET price = price * 0.9 WHERE category_id = 1;COMMIT;
在这个例子中,事务开始时使用
SELECT ... FOR UPDATE
语句获取了category_id
为1的产品行的排他锁,随后执行更新操作需要将行级锁升级为表级锁。 -
从共享锁升级到排他锁:
例子:
START TRANSACTION; SELECT * FROM products WHERE category_id = 1 LOCK IN SHARE MODE; -- 此时事务持有了共享锁-- 执行一些操作,需要将共享锁升级到排他锁 UPDATE products SET quantity = quantity - 1 WHERE category_id = 1;COMMIT;
在这个例子中,事务开始时使用
LOCK IN SHARE MODE
语句获取了category_id
为1的产品行的共享锁,但在后续执行中需要对该行进行修改,因此需要将共享锁升级为排他锁。 -
从意向锁升级到表级锁:
例子:
START TRANSACTION; SELECT * FROM orders WHERE customer_id = 100 FOR UPDATE; -- 此时事务持有了意向排他锁-- 执行一些操作,需要将意向锁升级为表级锁 DELETE FROM orders WHERE customer_id = 100;COMMIT;
在这个例子中,事务开始时使用
SELECT ... FOR UPDATE
语句获取了customer_id
为100的订单行的意向排他锁,后续执行了删除操作,需要将意向锁升级为表级锁。
相关文章:

MySQL-锁:共享锁(读)、排他锁(写)、表锁、行锁、意向锁、间隙锁,锁升级
MySQL-锁:共享锁(读)、排他锁(写)、表锁、行锁、意向锁、间隙锁 共享锁(读锁)、排他锁表锁行锁意向锁间隙锁锁升级 MySQL数据库中的锁是控制并发访问的重要机制,它们确保数据的一致性…...

docker 使用官方镜像搭建 PHP 环境
一、所需环境: 1、PHP:7.4.33-fpm 的版本 2、Nginx:1.25.1 的版本 3、MySQL: 5.7 的版本 4、Redis:7.0 的版本 1.1、拉取官方的镜像 docker pull php:7.4.33-fpm docker pull nginx:1.25.1 docker pull mysql:5.7 do…...

STM32CubeIDE基础学习-STM32CubeIDE软件偏好设置
STM32CubeIDE基础学习-STM32CubeIDE软件偏好设置 文章目录 STM32CubeIDE基础学习-STM32CubeIDE软件偏好设置前言第1章 设置字体颜色第2章 设置字体大小第3章 设置代码区背景颜色总结 前言 编程软件环境最好就设置一个自己喜欢的界面进行显示,这样看起来会比较舒服些…...
【《高性能 MySQL》笔记】性能优化
学习知识最快最好的方式就是问对问题。 本文将通过“问正确的问题”的方式循序渐进地深入总结性能优化相关知识。 性能优化基础 Q1:什么是“性能”? 即响应时间(RT,Response Time),完成某个任务所需要的时间度量。 Q2:什么是“性能优化”? 性能优化为在一定工作负…...

Spring AOP底层原理
目录 代理模式 静态代理 动态代理 1. JDK动态代理 创建⼀个代理对象并使用 2. CGLIB动态代理 SpringAOP底层原理面试 代理模式 Spring AOP是基于动态代理模式来实现的 代理模式:静态代理模式动态代理模式 代理模式, 也叫委托模式。 定义:为其…...
proteus8.9 示波器放大
proteus8.9 示波器放大** 1. 打开放大:Windows徽标键 加号 2. 取消放大:Windows徽标键 ESC...

代码随想录训练营第41天 | 动态规划:01背包理论基础、动态规划:01背包理论基础(滚动数组)、LeetCode 416.分割等和子集
动态规划:01背包理论基础 文章讲解:代码随想录(programmercarl.com) 视频讲解:带你学透0-1背包问题!_哔哩哔哩_bilibili 动态规划:01背包理论基础(滚动数组) 文章讲解:代码随想录(…...

1908_Arm Cortex-M3的实现
1908_Arm Cortex-M3的实现 全部学习汇总: g_arm_cores: ARM内核的学习笔记 (gitee.com) 这是第一次看一份这样的手册,之前的MCU编程基本上就是专注于软件接口方面。而OS等方面的一些功能基本上都是用了现成的解决方案,因此也就没有过多的关注…...
编程笔记 html5cssjs 005 小学数学四则运算练习
编程笔记 html5&css&js 005 小学数学四则运算练习 一、代码二、解释 这段代码定义了一个页面,用于小学数学四则运算的练习。这可能有点难,实际如果需要可以通过更改代码来达到要求。 一、代码 <!DOCTYPE html> <html lang"zh&quo…...

【大厂AI课学习笔记NO.71】AI算力芯片GPU/TPU等
AI算力芯片的发展历程 人工智能(AI)算力芯片的发展历程紧密地跟随着AI技术的发展脚步。从早期的基于传统中央处理器(CPU)的计算,到图形处理器(GPU)的广泛应用,再到专门为AI设计的处…...

浅谈Redis和分布式系统
浅谈Redis Redis用于存储数据,且在内存当中进行存储。 但是在日常编写代码中,定义一个变量也就属于在内存当中存储一个数据。 Redis主要会在分布式系统当中发挥重要作用,如果只是单机程序,直接通过变量存储数据的方式会比使用Re…...

微信小程序onLoad加载定义好的函数
这里小程序开发中容易犯的错误-1 给客户做一个程序。需要在页面加载的时候在onLoad(options){}中加载定义好的函数,代码如下 onLoad(options) {get_week_()},运行时老报错 后来修改为正确的代码 onLoad(options) {this.get_week_()//必须加this},再尝试运行&#x…...

C++进阶:详细讲解继承
现在也是结束了初阶部分的内容,今天开始就进入进阶部分了。一刻也没有为初阶的结束而哀悼,立刻赶来“战场”的是进阶部分里的继承 文章目录 1.继承的概念和定义1.1继承的概念1.2继承的定义1.2.1继承的格式1.2.2再讲访问限定符(详讲protected)1.2.3**继承…...

第十一篇 - 应用于市场营销视频场景中的人工智能和机器学习技术 – Video --- 我为什么要翻译介绍美国人工智能科技巨头IAB公司(1)
IAB平台,使命和功能 IAB成立于1996年,总部位于纽约市。 作为美国的人工智能科技巨头社会媒体和营销专业平台公司,互动广告局(IAB- the Interactive Advertising Bureau)自1996年成立以来,先后为700多家媒体…...

基于决策树实现葡萄酒分类
基于决策树实现葡萄酒分类 将葡萄酒数据集拆分成训练集和测试集,搭建tree_1和tree_2两个决策树模型,tree_1使用信息增益作为特征选择指标,B树使用基尼指数作为特征选择指标,各自对训练集进行训练,然后分别对训练集和测…...

上位机图像处理和嵌入式模块部署(qmacvisual三个特色)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 了解了qmacvisual的配置之后,正常来说,我们需要了解下不同插件的功能是什么。不过我们不用着急,可以继续学习下…...

电脑解锁后黑屏有鼠标--亲测!!不需要重装系统!!
问题:上周电脑黑屏,只有鼠标,鼠标还不能右键!! 中招:win10系统最新版火绒安全 ,那你有概率获得开机黑屏套餐一份。 原因是:火绒把我们的explorer删除了导致黑屏,这个文…...
Spring 事务的种类 ? 传播机制 ?
在Spring框架中,事务管理可以分为编程式事务和声明式事务两种主要形式。每种形式都有其特点和使用场景。以下是这两种形式的具体介绍: 编程式事务 编程式事务是通过编写代码来实现事务管理的。在Spring中,编程式事务管理通常通过Transactio…...
深入了解 Java 方法和参数的使用方法
Java 方法 简介 方法是一块仅在调用时运行的代码。您可以将数据(称为参数)传递到方法中。方法用于执行特定的操作,它们也被称为函数。 使用方法的原因 重用代码:定义一次代码,多次使用。提高代码的结构化和可读性。…...

自动驾驶技术解析与关键步骤
目录 前言1 自动驾驶主要技术流程1.1 车辆周围环境感知1.2 车辆和行人检测分析1.3 运动轨迹规划 2 关键技术概述2.1 车辆探测与图片输入2.2 行人检测2.3 运动规划2.4 电子地图2.5 轨迹预测2.6 交通灯分析2.7 故障检测 结语 前言 自动驾驶汽车作为未来交通领域的重要发展方向&a…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...

linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...

并发编程 - go版
1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程,系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...

Axure 下拉框联动
实现选省、选完省之后选对应省份下的市区...