Skip to content

for share 和 for update 有什么区别?

约 890 字大约 3 分钟

MySQL字节

2025-03-20

⭐ 题目日期:

字节 - 2024/12/17

📝 题解:

在 MySQL 中,FOR SHAREFOR UPDATE 是两种显式加锁的语句,用于控制事务并发访问数据时的行为。它们的核心区别在于 锁类型使用场景,以下是详细对比:


1. 锁类型与兼容性

语句锁类型锁兼容性
FOR SHARE共享锁(S Lock)- 允许其他事务加 FOR SHARE
- 禁止其他事务加 FOR UPDATE 或修改数据。
FOR UPDATE排他锁(X Lock)- 禁止其他事务加任何锁(包括 FOR SHAREFOR UPDATE)或修改数据。

2. 核心行为对比

特性FOR SHAREFOR UPDATE
读操作允许其他事务读允许其他事务读(但部分场景可能被阻塞)
写操作禁止其他事务修改数据禁止其他事务修改数据
锁范围共享锁(Next-Key Lock 或行锁)排他锁(Next-Key Lock 或行锁)
并发性能高(允许多事务同时读)低(完全独占资源)
典型场景需要读取数据并防止被修改(如生成报表)需要修改数据(如更新订单状态)

3. 使用场景示例

场景 1:数据读取保护(FOR SHARE)

  • 需求:事务 A 需要读取用户余额,并确保在事务提交前其他事务不能修改该余额。
  • 操作
    BEGIN;
    -- 加共享锁,允许其他事务读,但禁止修改
    SELECT balance FROM accounts WHERE user_id = 1 FOR SHARE;
    -- 其他事务可以执行 SELECT ... FOR SHARE,但不能执行 UPDATE 或 SELECT ... FOR UPDATE
    COMMIT;

场景 2:数据修改保护(FOR UPDATE)

  • 需求:事务 A 需要扣减库存,并确保在事务提交前其他事务不能修改库存。
  • 操作
    BEGIN;
    -- 加排他锁,禁止其他事务读写
    SELECT stock FROM products WHERE id = 100 FOR UPDATE;
    UPDATE products SET stock = stock - 1 WHERE id = 100;
    COMMIT;

4. 锁的底层行为

4.1 锁的粒度

  • 默认锁类型:Next-Key Lock(行锁 + 间隙锁),防止幻读。
  • 退化为行锁:如果查询条件命中唯一索引且精确匹配单行,退化为行锁(无间隙锁)。
  • 退化为表锁:如果无索引,可能锁全表(性能极差)。

4.2 锁的释放时机

  • 两种锁均在事务提交或回滚时释放。

5. 注意事项

5.1 死锁风险

  • FOR SHARE:多个事务同时持有共享锁,若某个事务尝试升级为排他锁(如 UPDATE),可能死锁。
  • FOR UPDATE:多个事务按不同顺序加排他锁可能死锁。
  • 解决方案:统一加锁顺序,或设置合理的超时时间(innodb_lock_wait_timeout)。

5.2 性能影响

  • FOR SHARE:适合读多写少场景,允许高并发读。
  • FOR UPDATE:写操作频繁时易引发锁竞争,需谨慎使用。

6. 总结

维度FOR SHAREFOR UPDATE
锁类型共享锁(S Lock)排他锁(X Lock)
读兼容性允许其他事务读允许其他事务读(但可能被阻塞)
写兼容性禁止其他事务写禁止其他事务写
使用场景保护数据读取一致性保护数据修改原子性
性能影响高并发读低并发,高独占性

关键结论

  • 使用 FOR SHARE 保护 只读操作 的共享访问,适用于读多写少场景。
  • 使用 FOR UPDATE 保护 写操作 的独占性,适用于数据强一致性要求的修改场景。
  • 合理选择锁类型,避免过度加锁导致性能下降或死锁。