意向锁(Intention Lock)
文章目录
- 意向锁(Intention Lock)
- 简介
- 类型
- 原理
- 意向锁加锁流程
- 锁兼容矩阵
- 使用场景
- 示例
- 总结
- 扩展:意向锁和共享锁排他锁的加锁流程
- 假设的场景和前提
- 已加锁的情况
- 新的加锁请求
- 加锁流程
- 锁的兼容性矩阵
- 示例代码
- 总结
文章目录
- 意向锁(Intention Lock)
- 简介
- 类型
- 原理
- 意向锁加锁流程
- 锁兼容矩阵
- 使用场景
- 示例
- 总结
- 扩展:意向锁和共享锁排他锁的加锁流程
- 假设的场景和前提
- 已加锁的情况
- 新的加锁请求
- 加锁流程
- 锁的兼容性矩阵
- 示例代码
- 总结
简介
MySQL 中的意向锁(Intention Lock)是一种表级锁,用于帮助协调不同粒度的锁(行级锁和表级锁)之间的冲突,优化并发事务的锁管理。意向锁并不会实际阻止行的读写操作,而是用来表明事务接下来要在某些行上加锁,从而提高锁冲突检测的效率。
类型
MySQL 中主要有两种类型的意向锁:
- 意向共享锁(Intention Shared Lock, IS):事务计划在某些行上加共享锁。
- 意向排他锁(Intention Exclusive Lock, IX):事务计划在某些行上加排他锁。
原理
当一个事务请求获取一个行级锁或表级锁时,MySQL会自动获取相应的表的意向锁。 这样,其他事务请求获取表锁时,就可以先基于这个意向锁来发现是否有人加过锁,并根据该锁的类型(意向共享锁/意向排他锁)来判断自己是否可以获取锁。通过这种方式,当一个事务请求表级锁时,InnoDB 可以快速确定是否有任何行级锁冲突,而无需检查表中每一行的锁状态。
注意:
- 意向锁并不是直接锁定资源,而是为了通知其他事务,以防止它们在资源上设置不兼容的锁。
- 意向锁并不是直接由用户请求的,而是由 MySQL 管理的。
意向锁加锁流程
- 事务请求意向锁:事务发出加意向锁的请求(IS或IX)。
- 检查兼容性:MySQL 检查意向锁是否与当前表上的其他意向锁或表级锁兼容。如果兼容,则加锁成功。
- 后续加锁操作:事务在行级别上加共享锁或排他锁时,只需检查意向锁而无需检查整个表。
- 释放锁:事务提交或回滚后,释放意向锁。
锁兼容矩阵
IS | IX | S | X | |
---|---|---|---|---|
IS | Yes | Yes | Yes | No |
IX | Yes | Yes | No | No |
S | Yes | No | Yes | No |
X | No | No | No | No |
- IS 和 IS 是兼容的,可以同时存在。
- IS 和 IX 是兼容的,可以同时存在。
- IX 和 IX 是兼容的,可以同时存在。
- S 和 IS 是兼容的,可以同时存在。
- S 和 IX 以及 X 锁都是不兼容的。
使用场景
意向锁在以下场景中非常有用:
- 高并发读写场景:在高并发读写操作中,意向锁减少了锁冲突检测的开销,提高了系统的并发性能。
- 行级锁与表级锁混合使用:当事务需要在行级别加锁但可能会有其他事务请求表级锁时,意向锁有助于快速检测冲突。
示例
假设有一个表 orders
,包含以下数据:
CREATE TABLE orders (id INT PRIMARY KEY,product_name VARCHAR(50),quantity INT
);
-
事务1:
START TRANSACTION; -- 请求在 orders 表上加意向排他锁 SELECT * FROM orders WHERE id = 1 FOR UPDATE;
-
事务2:
START TRANSACTION; -- 请求在 orders 表上加意向共享锁 SELECT * FROM orders WHERE id = 2 LOCK IN SHARE MODE;
-
事务3:
START TRANSACTION; -- 尝试加表级共享锁,会等待事务1和事务2释放意向锁 LOCK TABLES orders READ;
在以上示例中:
- 事务1在
orders
表上加了意向排他锁(IX)和行级排他锁(X)。 - 事务2在
orders
表上加了意向共享锁(IS)和行级共享锁(S)。 - 事务3尝试加表级共享锁(S),由于表上已有意向排他锁(IX),因此会等待事务1释放锁。
总结
**意向锁在 MySQL 中的作用是优化锁管理,减少锁冲突检测的开销,提升系统的并发性能。**它们在高并发读写场景和行级锁与表级锁混合使用场景中特别有用,通过表明事务的锁意图,使得锁冲突检测更加高效。
个人理解:
- 意向锁本质还是共享锁和排它锁
- 根据 SQL 要添加共享锁还是排它锁,MySQL 自动添加意向共享锁和意向排它锁
- 意向锁是表级锁,且是 MySQL的自动添加的,人为不可控。
扩展:意向锁和共享锁排他锁的加锁流程
在 MySQL 中,如果一个事务已经对 table
表的 id=1
记录添加了行级排他锁(A),而此时另一个事务要对同一个表的 id=5
记录添加行级排他锁(B),加锁流程将涉及意向锁和排他锁的处理。以下是详细的加锁流程:
假设的场景和前提
假设表结构如下:
CREATE TABLE table (id INT PRIMARY KEY,value VARCHAR(50)
);
已加锁的情况
- 事务 A 已经对
id=1
的记录添加了行级排他锁(X 锁)。
新的加锁请求
- 事务 B 尝试对
id=5
的记录添加行级排他锁(X 锁)。
加锁流程
- 事务 B 请求意向排他锁(IX 锁):
- 首先,事务 B 将在表
table
上尝试加意向排他锁(IX 锁),以表明接下来会在某些行上加排他锁。
- 首先,事务 B 将在表
- 检查意向锁的兼容性:
- 意向排他锁(IX 锁)与其他意向排他锁(IX 锁)和意向共享锁(IS 锁)都是兼容的,因此可以成功加锁。
- 意向排他锁(IX 锁)与表级共享锁(S 锁)和表级排他锁(X 锁)不兼容,但此处没有表级锁冲突。
- 请求行级排他锁(X 锁):
- 事务 B 发出对
id=5
记录加排他锁(X 锁)的请求。 - MySQL 检查行级锁的兼容性。由于
id=5
的记录当前没有被其他事务加锁,排他锁(X 锁)可以成功加锁。(如果此时事务 B 对id=1
添加行级锁,那么事务 B 会被阻塞,直到事务 A 释放了行级锁)
- 事务 B 发出对
- 加锁成功:
- 事务 B 成功对
id=5
的记录加上排他锁(X 锁)。
- 事务 B 成功对
锁的兼容性矩阵
为了更好地理解意向锁和行级锁的兼容性,以下是锁的兼容性矩阵:
锁类型 | IS | IX | S | X |
---|---|---|---|---|
IS | Yes | Yes | Yes | No |
IX | Yes | Yes | No | No |
S | Yes | No | Yes | No |
X | No | No | No | No |
示例代码
以下是一个具体示例代码来说明上述流程:
-
事务 A:
START TRANSACTION; -- 对 id=1 的记录加排他锁 SELECT * FROM table WHERE id = 1 FOR UPDATE; -- 行级排他锁 X
-
事务 B:
START TRANSACTION; -- 对 id=5 的记录加排他锁 SELECT * FROM table WHERE id = 5 FOR UPDATE; -- 行级排他锁 X
在这个示例中:
- 事务 A 对
id=1
的记录加了排他锁(X 锁)。 - 事务 B 对
id=5
的记录加了排他锁(X 锁)。
总结
- 意向排他锁(IX 锁):
- 事务 B 需要在表
table
上加意向排他锁(IX 锁)。由于 IX 锁之间是兼容的,并且没有表级别的锁冲突,IX 锁加锁成功。
- 事务 B 需要在表
- 行级排他锁(X 锁):
- 事务 B 对
id=5
的记录加行级排他锁(X 锁),由于id=5
没有被其他事务锁定,所以排他锁加锁成功。
- 事务 B 对
这整个过程确保了即使在高并发环境下,事务之间能够协调操作,避免数据冲突和不一致。通过意向锁和行级锁的配合,MySQL 能够有效地管理并发事务对数据库的访问和操作。