Skip to content

这个锁是怎么记录的,存在哪里?

约 1169 字大约 4 分钟

MySQL快手

2025-03-19

⭐ 题目日期:

快手 - 2024/12/29

📝 题解:

在 InnoDB 存储引擎中,锁的管理和记录是通过 内存数据结构事务系统 实现的。锁信息不会持久化到磁盘,而是存储在内存中,并通过事务的生命周期动态管理。以下是锁的记录方式和存储位置的详细说明:


一、锁的存储位置

1. 内存中的锁结构

  • 锁对象(Lock Struct): InnoDB 为每个被锁定的资源(如行记录、间隙)在内存中创建一个锁结构(lock_t),包含以下信息:
    • 锁类型:行锁(Record Lock)、间隙锁(Gap Lock)、临键锁(Next-Key Lock)等。
    • 事务信息:持有该锁的事务指针(trx_t)。
    • 锁定的资源标识:如记录的索引位置、间隙范围。
    • 锁模式:共享锁(S锁)或排他锁(X锁)。
  • 全局锁表(Lock Table): 所有活跃的锁对象通过哈希表组织,哈希键由 锁定的资源标识(如空间 ID、页号、记录位置)生成,便于快速查找。

2. 事务系统

  • 事务对象(trx_t): 每个事务维护一个锁链表,记录该事务持有的所有锁对象。
    • 事务提交或回滚时,会遍历链表释放所有锁。

3. 数据字典

  • 索引结构: InnoDB 的索引(B+树)中存储了记录的物理位置信息,锁的申请基于索引定位到具体的记录或间隙。

二、锁的记录方式

锁的具体记录方式与 索引类型锁定范围 密切相关:

1. 行锁(Record Lock)

  • 锁定目标:索引中的具体记录(主键或二级索引)。
  • 记录方式
    • 对主键索引的记录加锁时,直接锁定主键对应的行。
    • 对二级索引的记录加锁时,会同时锁定二级索引项和对应的主键索引项(防止通过其他索引路径修改数据)。

2. 间隙锁(Gap Lock)

  • 锁定目标:索引记录的间隙范围(区间)。
  • 记录方式
    • 例如,锁定 (5, 10) 的间隙,阻止其他事务插入 id=6id=9 的值。
    • 间隙锁仅存在于 REPEATABLE READ 隔离级别。

3. 临键锁(Next-Key Lock)

  • 锁定目标:行锁 + 间隙锁的组合(锁定记录及其之前的间隙)。
  • 记录方式
    • 例如,锁定 (5, 10],即间隙 (5, 10) 和记录 10
    • 默认的锁模式,用于防止幻读。

三、锁的申请与释放流程

1. 申请锁

  1. 事务通过索引定位到需要锁定的记录或间隙。
  2. 检查内存中的锁表,判断是否存在冲突的锁(如其他事务已持有排他锁)。
  3. 若无冲突,创建锁对象并加入事务的锁链表和全局锁表。
  4. 若存在冲突,事务进入等待状态,直到锁被释放或超时。

2. 释放锁

  • 事务提交或回滚: 释放事务持有的所有锁对象,并从全局锁表中删除。
  • 显式释放: 某些场景下(如悲观锁提前释放),可通过 ROLLBACKCOMMIT 释放锁。

四、锁的可见性与监控

1. 查看锁信息

通过以下方式监控当前锁状态:

  • SHOW ENGINE INNODB STATUS: 输出 TRANSACTIONS 部分,显示活跃事务和锁信息。

    SHOW ENGINE INNODB STATUS;
  • information_schema 系统表

    -- 查看当前活跃的锁
    SELECT * FROM information_schema.INNODB_LOCKS;
    
    -- 查看锁等待关系
    SELECT * FROM information_schema.INNODB_LOCK_WAITS;

2. 示例输出

--- TRX HAS BEEN WAITING 5 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 12345 page no 7 n bits 80 index PRIMARY of table `test`.`t`
trx id 67890 lock_mode X locks rec but not gap waiting

五、锁的优化与注意事项

  1. 索引设计
    • 为查询条件添加合适的索引,避免全表扫描导致的表级锁。
    • 唯一索引减少间隙锁的冲突范围。
  2. 事务设计
    • 尽量缩短事务长度,减少锁持有时间。
    • 避免在事务中执行耗时操作(如网络调用)。
  3. 隔离级别选择
    • 根据业务需求选择最低隔离级别(如 READ COMMITTED 可减少间隙锁)。
  4. 监控与调优
    • 定期检查锁等待和死锁日志(SHOW ENGINE INNODB STATUS)。
    • 配置 innodb_lock_wait_timeout 控制锁等待超时时间。

六、总结

  • 锁的存储:内存中的锁对象(lock_t)和事务系统(trx_t)动态管理。
  • 锁的记录:基于索引结构,通过行锁、间隙锁、临键锁保护数据完整性。
  • 核心价值:通过细粒度锁机制实现高并发事务的隔离性,但需合理设计索引和事务,避免性能问题。