Bohr-L Bohr-L
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

刘博

I'm a slow walker, But I never walk backwards.
首页
技术
常见面试题
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 数据处理与存储类

  • Spring 生态类

  • 缓存问题类

  • 多线程类

  • JVM 类

  • MySQL 类

    • MySQL 为什么一定要有一个主键
    • MySQL 中的 RR 隔离级别,到底有没有解决幻读问题
    • MySQL 的行级锁到底锁的是什么东西?
      • 存储 MD5 值应该用 VARCHAR 还是用 CHAR?
      • 数据库的三范式是什么?
      • 说说 InnoDB 与 MyISAM 的区别
      • drop、truncate、delete 的区别
      • 聊一聊数据库事务机制
      • 聊一聊 MySQL 中的关联查询
      • 事务隔离级别有哪些?MySQL 的默认隔离级别是什么
      • 分库分表之后,id 主键如何处理?
      • 说说在 MySQL 中一条查询 SQL 是如何执行的?
      • 讲解下 DDL、DML、DCL
      • 存储过程和触发器的作用
      • MySQL 如何行转列和列转行
      • 如何查看 SQL 的执行计划
      • union 和 unionAll 的区别
      • having 和 where 的区别
      • 常见的索引原则
      • MySQL 中的 IN 和 EXISTS 子句有什么区别?
      • MySQL 如何处理 NULL 值,对性能有什么影响?
      • 如何在 MySQL 中处理和避免全表扫描?
      • MySQL 中的表空间是什么,它的作用是什么?
      • 在 MySQL 中,如何优化 ORDER BY 查询?
    • Java 8 + 特性类

    • 其他技术类

    • 常见面试题
    • MySQL 类
    刘博
    2025-12-29
    目录

    MySQL 的行级锁到底锁的是什么东西?

    MySQL 的行级锁(Row-Level Lock)是InnoDB 存储引擎特有的锁机制,用于锁定表中的 “单行数据”,但本质上 “锁的是索引记录,而非物理行”,具体锁对象和机制如下:

    # 1. 行级锁的核心:锁索引记录

    InnoDB 采用 “聚簇索引” 结构,数据和索引紧密关联,行级锁的锁定对象是 “索引记录”,而非直接锁定物理行(磁盘上的行数据):

    • 若表有显式主键(如id),行级锁锁定 “主键索引记录”;
    • 若表无显式主键,但有非空唯一索引(如phone),行级锁锁定 “非空唯一索引记录”;
    • 若表无主键和非空唯一索引,行级锁锁定 InnoDB 生成的隐藏row_id索引记录;
    • 示例:执行UPDATE user SET name='zhangsan' WHERE id=100,InnoDB 会锁定主键索引中id=100的记录,而非直接锁定物理行。

    # 2. 行级锁的类型

    InnoDB 的行级锁分为两类,对应不同的操作场景:

    # (1)共享锁(S 锁,Shared Lock)
    • 作用:允许事务读取数据,多个事务可同时持有同一行的 S 锁(“读共享”);
    • 获取方式:执行SELECT ... LOCK IN SHARE MODE;
    • 兼容性:与 S 锁兼容(多个事务可同时加 S 锁),与 X 锁互斥(加 S 锁后,其他事务无法加 X 锁,反之亦然);
    • 使用场景:需要确保数据读取时不被修改(如统计数据时,防止其他事务修改数据导致统计结果不准确)。
    # (2)排他锁(X 锁,Exclusive Lock)
    • 作用:允许事务修改或删除数据,同一行数据仅允许一个事务持有 X 锁(“写排他”);
    • 获取方式:执行INSERT/UPDATE/DELETE或SELECT ... FOR UPDATE;
    • 兼容性:与 S 锁、X 锁均互斥(加 X 锁后,其他事务无法加 S 锁或 X 锁);
    • 使用场景:修改或删除数据时,防止其他事务同时修改(如更新用户余额时,避免并发更新导致余额错误)。

    # 3. 行级锁的锁定范围:Next-Key Lock(行锁 + 间隙锁)

    在 RR 隔离级别下,InnoDB 为避免幻读,会将行级锁扩展为 “Next-Key Lock”,即 “行锁 + 间隙锁”,锁定范围包括 “已存在的行” 和 “行之间的间隙”:

    • 行锁:锁定已存在的索引记录(如id=100的行);
    • 间隙锁:锁定索引记录之间的间隙(如id=100和id=200之间的间隙),防止其他事务在间隙中插入数据;
    • 示例:
      • 表user的id值为 100、200、300;
      • 执行SELECT * FROM user WHERE id > 100 FOR UPDATE,InnoDB 会锁定:
        1. 行锁:id=200、id=300的索引记录;
        2. 间隙锁:100~200、200~300、300~+∞的间隙;
      • 其他事务无法插入id=150、id=250等数据,避免幻读。

    # 4. 行级锁的释放时机

    • 行级锁由事务控制,事务提交(COMMIT)或回滚(ROLLBACK)时释放,而非语句执行完成后释放;

    • 示例:

      BEGIN; -- 事务启动
      UPDATE user SET name='zhangsan' WHERE id=100; -- 加X锁
      -- 此时,其他事务执行`UPDATE user SET name='lisi' WHERE id=100`会被阻塞
      COMMIT; -- 事务提交,释放X锁
      -- 其他事务可正常执行更新
      
      1
      2
      3
      4
      5

    # 5. 行级锁的常见问题:间隙锁导致的死锁

    由于 Next-Key Lock 的存在,若两个事务在同一间隙加锁,可能导致死锁:

    • 示例:
      1. 事务 A:UPDATE user SET name='a' WHERE id=150(锁定100~200间隙);
      2. 事务 B:UPDATE user SET name='b' WHERE id=160(尝试锁定100~200间隙,被事务 A 阻塞);
      3. 事务 A:UPDATE user SET name='c' WHERE id=160(尝试锁定100~200间隙,被事务 B 阻塞);
      4. 两个事务互相等待,导致死锁;
    • 解决方案:
      1. 尽量使用主键或唯一索引作为查询条件,减少间隙锁的范围;
      2. 控制事务大小,缩短事务执行时间,减少锁持有时间;
      3. 避免在同一间隙中并发执行更新操作。

    上次更新: 12/30/2025
    MySQL 中的 RR 隔离级别,到底有没有解决幻读问题
    存储 MD5 值应该用 VARCHAR 还是用 CHAR?

    ← MySQL 中的 RR 隔离级别,到底有没有解决幻读问题 存储 MD5 值应该用 VARCHAR 还是用 CHAR?→

    最近更新
    01
    CPU 使用率较高排查和解决
    12-29
    02
    JVM OOM 问题如何排查和解决
    12-29
    03
    接口防刷怎么实现?
    12-29
    更多文章>
    Theme by Vdoing | Copyright © 2025-2026 Bohr-L's note
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式