MySQL InnoDB 行锁

前言

InnoDB 行锁是 MySQL 的 InnoDB 存储引擎提供的一种锁机制,用于实现事务的并发控制,保证数据的一致性和完整性

行锁

正如其名,是对一行数据进行加锁,当一个事务 A 对记录 r 加上行锁之后,可以对记录 r 进行修改,在释放行锁之前,其他事务无法获取记录 r 的行锁进行修改。

行锁是读锁还是写锁?

行锁分为 共享锁排它锁,共享锁可以多个事务同时获取,进行读取数据;而排它锁,同一时间只能有一个事务能获取成功,获取成功之后便可对数据记录进行修改操作。

行锁

行锁类型

共享锁(S 锁)

允许事务读取一行数据。多个事务可以同时对同一行数据加共享锁,也就是共享锁之间是兼容的。

若事务 A 对某行数据加上共享锁,那么事务 B 也可以对这行数据加共享锁进行读取操作,但在所有共享锁释放之前,任何事务都不能对这行数据加排他锁进行写操作。

排他锁(X 锁)

允许事务更新或删除一行数据。一旦一个事务对某行数据加上排他锁,其他事务就不能再对这行数据加任何类型的锁,直到该排他锁被释放。

排他锁与共享锁的兼容性

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

可以看到的是 X锁与任何的锁都不兼容,而 S 锁仅和 S 锁兼容。

注:S 和 X 都是行锁,兼容是指对同一记录锁的兼容性情况。

加锁方式

隐式加锁

在执行 UPDATEDELETE 等修改数据的语句时,InnoDB 会自动对涉及的行记录加上排他锁。例如:

sql 复制代码
UPDATE your_table SET column1 = 'new_value' WHERE id = 1;

此语句执行时,InnoDB 会自动对 id = 1 的行记录加上排他锁。

显式加锁

可以使用特定的 SQL 语句来显式地加锁。

  • 共享锁 :使用 SELECT ... LOCK IN SHARE MODE 语句,示例如下:
sql 复制代码
SELECT * FROM your_table WHERE id = 1 LOCK IN SHARE MODE;

该语句会对 id = 1 的行记录加上共享锁。

排他锁

使用 SELECT ... FOR UPDATE 语句,示例如下:

sql 复制代码
SELECT * FROM your_table WHERE id = 1 FOR UPDATE;

此语句会对 id = 1 的行记录加上排他锁。

行锁特点

粒度小

相比于表锁,行锁的粒度更小,只对需要操作的行进行加锁,因此并发性能更高。不同事务可以同时对不同行进行操作,减少了锁冲突的概率。

开销大

行锁需要维护更多的锁信息,加锁和解锁的操作也更为复杂,因此会带来一定的性能开销。

在 InnoDB 的事务实现里,当两个事务都要对同一条数据进行修改时,持有锁的状态会持续到事务提交或者回滚,下面为你详细解释:

锁机制

InnoDB 采用了行级锁来管理并发事务对同一行数据的访问。当一个事务需要修改某条数据时,它会先尝试获取该行数据的排他锁(X 锁)。

排他锁的作用是阻止其他事务对同一行数据进行读取和修改操作,以此保证数据的一致性和完整性。

锁的持有时间

一旦事务成功获取到排他锁,就会一直持有该锁,直至事务完成。这里的事务完成有两种情况:

  • 事务提交 :当事务中的所有操作都成功执行,并且使用 COMMIT 语句提交事务时,事务会释放持有的所有锁。此时,其他事务就有机会获取该行数据的锁并进行操作。
  • 事务回滚 :若事务执行过程中出现错误或者满足特定条件需要撤销已执行的操作,使用 ROLLBACK 语句回滚事务,事务也会释放持有的所有锁。
sql 复制代码
-- 事务 1
START TRANSACTION;
-- 事务 1 获取排他锁并修改数据
UPDATE your_table SET column1 = 'new_value' WHERE id = 1;
-- 此时事务 1 持有锁,直到提交或回滚

-- 事务 2
START TRANSACTION;
-- 事务 2 尝试修改同一行数据,会被阻塞,直到事务 1 提交或回滚
UPDATE your_table SET column1 = 'another_value' WHERE id = 1;

-- 事务 1 提交
COMMIT;
-- 事务 1 释放锁,事务 2 可以继续执行并获取锁

综上所述,在 InnoDB 中,事务对锁的持有会持续到事务提交或者回滚,这样能确保并发事务对同一行数据的操作是串行化的,从而保证数据的一致性和完整性。

锁的兼容性

InnoDB 中的锁有不同的类型,并且存在锁的兼容性规则,用于管理多个事务对同一资源的并发访问。在这些规则中,排他锁和其他类型的锁是不兼容的。具体情况如下:

排他锁(X) 共享锁(S) 意向排他锁(IX) 意向共享锁(IS)
排他锁(X) 冲突 冲突 冲突 冲突
共享锁(S) 冲突 兼容 兼容 兼容
意向排他锁(IX) 冲突 兼容 兼容 兼容
意向共享锁(IS) 冲突 兼容 兼容 兼容
相关推荐
PP东4 分钟前
Flowable学习(二)——Flowable概念学习
java·后端·学习·flowable
invicinble13 分钟前
springboot的核心实现机制原理
java·spring boot·后端
Goat恶霸詹姆斯18 分钟前
mysql常用语句
数据库·mysql·oracle
全栈老石39 分钟前
Python 异步生存手册:给被 JS async/await 宠坏的全栈工程师
后端·python
大模型玩家七七41 分钟前
梯度累积真的省显存吗?它换走的是什么成本
java·javascript·数据库·人工智能·深度学习
曾经的三心草43 分钟前
redis-9-哨兵
数据库·redis·bootstrap
space62123271 小时前
在SpringBoot项目中集成MongoDB
spring boot·后端·mongodb
明哥说编程1 小时前
Dataverse自定义表查询优化:D365集成大数据量提速实战【索引配置】
数据库·查询优化·dataverse·dataverse自定义表·索引配置·d365集成·大数据量提速
xiaowu0801 小时前
C# 拆解 “显式接口实现 + 子类强类型扩展” 的设计思想
数据库·oracle
讯方洋哥1 小时前
HarmonyOS App开发——关系型数据库应用App开发
数据库·harmonyos