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) 冲突 兼容 兼容 兼容
相关推荐
l1t9 分钟前
测试DuckDB 2.1的match_recognize模式匹配语句
数据库·duckdb
名字还没想好☜27 分钟前
Go context.AfterFunc 实战(Go 1.21):context 一取消就自动跑清理,告别手写 goroutine 监听 Done
后端·golang·go
IpdataCloud1 小时前
AI智能体调用工具怎么核验来源IP?归属地、网络类型与代理风险识别(含Python代码)
数据库·python·tcp/ip
明月_清风1 小时前
为什么最近开始关注 JEV?几个实战案例告诉你答案
人工智能·后端
曹牧1 小时前
Java:SQL 注入漏洞
数据库
GetcharZp2 小时前
5 分钟拥有自己的 S3:RustFS 上手(MinIO 的 Rust 替代,Apache 2.0 可商用)
后端
程序员JerrySUN2 小时前
Jetson Edge AI 实战01:Nano、Xavier、Orin 怎么选?Jetson 硬件选型详解【视频讲解】
java·数据库·redis·安全·mybatis
oradh2 小时前
Oracle Undo问题总结(ORA-600 [4xxx] 系列错误)
数据库·oracle
达梦数据2 小时前
DMDRS辅助表生成规则与作用
数据库·oracle
‎ദ്ദിᵔ.˛.ᵔ₎3 小时前
MySQL 表约束
数据库·mysql