03_意向锁

意向锁(Intention Lock)


简介

MySQL 中的意向锁(Intention Lock)是一种表级锁,用于帮助协调不同粒度的锁(行级锁和表级锁)之间的冲突,优化并发事务的锁管理。意向锁并不会实际阻止行的读写操作,而是用来表明事务接下来要在某些行上加锁,从而提高锁冲突检测的效率。


类型

MySQL 中主要有两种类型的意向锁:

  1. 意向共享锁(Intention Shared Lock, IS):事务计划在某些行上加共享锁。
  2. 意向排他锁(Intention Exclusive Lock, IX):事务计划在某些行上加排他锁。

原理

当一个事务请求获取一个行级锁或表级锁时,MySQL会自动获取相应的表的意向锁。 这样,其他事务请求获取表锁时,就可以先基于这个意向锁来发现是否有人加过锁,并根据该锁的类型(意向共享锁/意向排他锁)来判断自己是否可以获取锁。通过这种方式,当一个事务请求表级锁时,InnoDB 可以快速确定是否有任何行级锁冲突,而无需检查表中每一行的锁状态。

注意:

  • 意向锁并不是直接锁定资源,而是为了通知其他事务,以防止它们在资源上设置不兼容的锁。
  • 意向锁并不是直接由用户请求的,而是由 MySQL 管理的。

意向锁加锁流程
  1. 事务请求意向锁:事务发出加意向锁的请求(IS或IX)。
  2. 检查兼容性:MySQL 检查意向锁是否与当前表上的其他意向锁或表级锁兼容。如果兼容,则加锁成功。
  3. 后续加锁操作:事务在行级别上加共享锁或排他锁时,只需检查意向锁而无需检查整个表。
  4. 释放锁:事务提交或回滚后,释放意向锁。

锁兼容矩阵
ISIXSX
ISYesYesYesNo
IXYesYesNoNo
SYesNoYesNo
XNoNoNoNo
  • ISIS 是兼容的,可以同时存在。
  • ISIX 是兼容的,可以同时存在。
  • IXIX 是兼容的,可以同时存在。
  • SIS 是兼容的,可以同时存在。
  • SIX 以及 X 锁都是不兼容的。

使用场景

意向锁在以下场景中非常有用:

  • 高并发读写场景:在高并发读写操作中,意向锁减少了锁冲突检测的开销,提高了系统的并发性能。
  • 行级锁与表级锁混合使用:当事务需要在行级别加锁但可能会有其他事务请求表级锁时,意向锁有助于快速检测冲突。

示例

假设有一个表 orders,包含以下数据:

CREATE TABLE orders (
    id INT PRIMARY KEY,
    product_name VARCHAR(50),
    quantity INT
);
  1. 事务1

    START TRANSACTION;
    -- 请求在 orders 表上加意向排他锁
    SELECT * FROM orders WHERE id = 1 FOR UPDATE;
    
  2. 事务2

    START TRANSACTION;
    -- 请求在 orders 表上加意向共享锁
    SELECT * FROM orders WHERE id = 2 LOCK IN SHARE MODE;
    
  3. 事务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 锁)。
加锁流程
  1. 事务 B 请求意向排他锁(IX 锁)
    • 首先,事务 B 将在表 table 上尝试加意向排他锁(IX 锁),以表明接下来会在某些行上加排他锁。
  2. 检查意向锁的兼容性
    • 意向排他锁(IX 锁)与其他意向排他锁(IX 锁)和意向共享锁(IS 锁)都是兼容的,因此可以成功加锁。
    • 意向排他锁(IX 锁)与表级共享锁(S 锁)和表级排他锁(X 锁)不兼容,但此处没有表级锁冲突。
  3. 请求行级排他锁(X 锁)
    • 事务 B 发出对 id=5 记录加排他锁(X 锁)的请求。
    • MySQL 检查行级锁的兼容性。由于 id=5 的记录当前没有被其他事务加锁,排他锁(X 锁)可以成功加锁。(如果此时事务 B 对 id=1 添加行级锁,那么事务 B 会被阻塞,直到事务 A 释放了行级锁)
  4. 加锁成功
    • 事务 B 成功对 id=5 的记录加上排他锁(X 锁)。
锁的兼容性矩阵

为了更好地理解意向锁和行级锁的兼容性,以下是锁的兼容性矩阵:

锁类型ISIXSX
ISYesYesYesNo
IXYesYesNoNo
SYesNoYesNo
XNoNoNoNo
示例代码

以下是一个具体示例代码来说明上述流程:

  1. 事务 A

    START TRANSACTION;
    -- 对 id=1 的记录加排他锁
    SELECT * FROM table WHERE id = 1 FOR UPDATE;  -- 行级排他锁 X
    
  2. 事务 B

    START TRANSACTION;
    -- 对 id=5 的记录加排他锁
    SELECT * FROM table WHERE id = 5 FOR UPDATE;  -- 行级排他锁 X
    

在这个示例中:

  • 事务 A 对 id=1 的记录加了排他锁(X 锁)。
  • 事务 B 对 id=5 的记录加了排他锁(X 锁)。
总结
  1. 意向排他锁(IX 锁)
    • 事务 B 需要在表 table 上加意向排他锁(IX 锁)。由于 IX 锁之间是兼容的,并且没有表级别的锁冲突,IX 锁加锁成功。
  2. 行级排他锁(X 锁)
    • 事务 B 对 id=5 的记录加行级排他锁(X 锁),由于 id=5 没有被其他事务锁定,所以排他锁加锁成功。

这整个过程确保了即使在高并发环境下,事务之间能够协调操作,避免数据冲突和不一致。通过意向锁和行级锁的配合,MySQL 能够有效地管理并发事务对数据库的访问和操作。


  • 36
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值