Plantre Plantre
首页
后端
技术
硬件
  • 前端文章

    • HTML
    • CSS
    • JavaScript
  • 技术

    • 技术文档
    • GitHub技巧
    • Nodejs
    • 博客搭建
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

plantre

一个后端开发者
首页
后端
技术
硬件
  • 前端文章

    • HTML
    • CSS
    • JavaScript
  • 技术

    • 技术文档
    • GitHub技巧
    • Nodejs
    • 博客搭建
  • 学习笔记

    • 《JavaScript教程》
    • 《JavaScript高级程序设计》
    • 《ES6 教程》
    • 《Vue》
    • 《React》
    • 《TypeScript 从零实现 axios》
    • 《Git》
    • TypeScript
    • JS设计模式总结
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 计算机组成原理

  • 操作系统

  • 计算机网络

  • 设计模式

  • Java

  • Spring

  • SpringCloud

  • MySQL

    • MySQL的权限控制
    • 精细权限管制示例
    • localhost和127.0.0.1的区别-MySQL
    • mysql数据类型
    • 当前读和快照读
    • MySQL中MVCC的实现原理
    • MySQL中MVCC具体用了多少个隐藏字段
    • 锁和事务的关系
    • FOR UPDATE锁类型
  • Redis

  • 分布式

  • Zookeeper

  • Dubbo

  • Kafka

  • 数据结构

  • 算法

  • OJ

  • 从道家哲学看计算机?
  • 后端
  • MySQL
plantre
2025-05-14

FOR UPDATE锁类型

关于 FOR UPDATE 的验证与分析

在 MySQL 中,SELECT ... FOR UPDATE 是一种悲观锁机制,用于在事务中锁定目标数据行或表,防止其他事务修改。其锁类型(行锁或表锁)及行为取决于查询条件、索引使用和事务隔离级别。以下是关键验证结论及操作方法:


一、验证锁类型的关键条件

  1. 主键或唯一索引
    • 条件:查询条件包含主键或唯一索引字段(如 id=1 或 account_no='0001')。

    • 行为:仅锁定符合条件的行(行锁),其他行的操作不受影响。

    • 验证步骤:

    -- 事务1:锁定主键为1的行
    BEGIN;
    SELECT * FROM user WHERE id = 1 FOR UPDATE;
    -- 事务2:尝试更新同一行(阻塞)
    UPDATE user SET age = 20 WHERE id = 1;
    -- 事务3:更新其他行(成功)
    UPDATE user SET age = 20 WHERE id = 2;
    
    1
    2
    3
    4
    5
    6
    7
  2. 普通索引或范围查询
    • 条件:查询条件为普通索引字段(如 user_name='user01')或范围(如 id IN (1,2))。

    • 行为:行锁 + 间隙锁(Gap Lock),防止其他事务插入符合条件的新数据(避免幻读)。

    • 验证步骤:

    -- 事务1:锁定普通索引字段
    BEGIN;
    SELECT * FROM user WHERE user_name = 'user01' FOR UPDATE;
    -- 事务2:尝试插入相同索引值的记录(阻塞)
    INSERT INTO user (user_name) VALUES ('user01');
    
    1
    2
    3
    4
    5
  3. 无索引的普通字段
    • 条件:查询条件为无索引字段(如 code='0001')。

    • 行为:锁定整张表(表锁),所有更新操作均阻塞。

    • 验证步骤:

    -- 事务1:锁定无索引字段
    BEGIN;
    SELECT * FROM user WHERE code = '0001' FOR UPDATE;
    -- 事务2:更新任意行(均阻塞)
    UPDATE user SET code = '0002' WHERE id = 2;
    
    1
    2
    3
    4
    5

二、锁类型的判断方法

  1. 观察阻塞行为
    • 若其他事务更新同一行数据被阻塞,则为行锁。

    • 若更新其他行数据也被阻塞,则为表锁。

  2. 查看锁信息
    执行以下 SQL 查询当前锁状态(需在事务阻塞时执行):

    SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCKS;
    
    1

    • 行锁:lock_type 为 RECORD,lock_data 显示锁定行的主键值。

    • 表锁:lock_type 为 TABLE,且无具体行信息。


三、事务隔离级别的影响

  1. 可重复读(RR)
    • 默认行为:InnoDB 默认隔离级别,使用行锁 + 间隙锁。

    • 验证场景:普通索引查询会锁定间隙,防止插入新数据(幻读)。

  2. 读已提交(RC)
    • 行为:仅锁定现有行,不锁定间隙,可能允许幻读。

    • 验证场景:在 RC 级别下,普通索引查询不会阻塞插入操作。


四、注意事项

  1. 性能与死锁
    • 锁范围最小化:尽量通过主键或索引缩小锁定范围,减少锁冲突。

    • 超时设置:通过 innodb_lock_wait_timeout 设置锁等待超时时间(默认 50 秒)。

    • 死锁检测:MySQL 自动检测死锁并回滚事务,但需优化事务执行顺序。

  2. 事务提交与回滚
    • 锁释放时机:事务提交(COMMIT)或回滚(ROLLBACK)后释放锁。

    • 自动提交模式:关闭自动提交(SET autocommit=0)以手动控制事务边界。


五、适用场景

  1. 金融交易:转账时锁定账户行,防止并发修改导致金额错误。
  2. 库存管理:扣减库存时锁定商品行,避免超卖。
  3. 订单处理:更新订单状态时确保原子性操作。

验证步骤总结

  1. 环境准备:创建含主键、唯一索引、普通索引和无索引字段的表。
  2. 关闭自动提交:SET autocommit=0。
  3. 多会话测试:通过多个数据库会话模拟并发操作,观察阻塞行为。
  4. 锁信息监控:结合 INNODB_LOCKS 表分析锁类型。

通过上述验证,可明确 FOR UPDATE 的锁机制,从而合理设计高并发场景下的数据访问逻辑。

编辑 (opens new window)
上次更新: 2025/06/13, 00:51:28
锁和事务的关系
redis的槽

← 锁和事务的关系 redis的槽→

最近更新
01
集成loki
07-04
02
TCP的ESTABLISHED是什么意思
06-24
03
安装1panel
06-24
更多文章>
Theme by Vdoing | Copyright © 2025-2025 plantre | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式