MySQL事务隔离级别及S与X锁

95 阅读3分钟

1. 假定某商品库存为10,数据库使用mysql的默认隔离级别,请问扣减一个库存同时,有一个查询,查询到的数据库存是多少?

🧠 分析过程

MySQL 默认隔离级别:REPEATABLE READ

MySQL InnoDB 的默认隔离级别是 可重复读(REPEATABLE READ) ,其核心特征:

  • 通过 MVCC(多版本并发控制) 实现;
  • 一个事务中多次读取同一行数据,结果一致(除非自己修改);
  • 未提交事务中修改的数据,其他事务看不到
  • 避免了脏读

🧾 举例分析

时间顺序操作说明
t1事务A开始扣减库存事务开始
t2事务A执行 UPDATE product SET stock = stock - 1 WHERE id = 1;将库存改为 9,但未提交
t3事务B执行 SELECT stock FROM product WHERE id = 1;查询库存
t4事务A提交扣减完成

🔍 t3 时刻:事务B 查询到的结果

因为 MySQL 在 REPEATABLE READ 隔离级别下,
事务B 看不到事务A未提交的修改(MVCC 保证),

所以:

✅ 事务B 查询到的库存 = 10

即使事务A已经执行了 UPDATE,但未提交,其他事务看到的仍是旧版本。

✅ 总结结论

项目说明
数据库隔离级别REPEATABLE READ(默认)
库存初始值10
事务A操作UPDATE stock = 9(未提交)
事务B操作SELECT stock
查询结果10
原因MVCC 保证读到的是已提交版本,避免脏读

💡 补充:如果换隔离级别会怎样

隔离级别查询结果原因
READ UNCOMMITTED9能读到未提交数据(脏读)
READ COMMITTED10只能读到已提交数据
REPEATABLE READ(默认)10使用快照读,读到的是事务开始时的版本
SERIALIZABLE10加锁读,阻塞直到事务A提交或回滚

2.数据库s锁与x锁

🧩 一、S锁与X锁的基本定义

锁类型全称英文名称作用
S锁共享锁Shared Lock允许多个事务同时读取同一行,但不允许修改
X锁排他锁Exclusive Lock只允许一个事务对该行进行读写,其他事务不能再加任何锁

🧠 二、加锁后的行为差异

操作类型需要的锁类型是否允许并发
SELECT ... LOCK IN SHARE MODES锁✅ 允许其他事务也加S锁(共享读) ❌ 不允许X锁(写)
SELECT ... FOR UPDATEX锁❌ 其他事务不能加任何锁(读写都阻塞)
UPDATE / DELETE / INSERTX锁❌ 独占该行
普通 SELECT(无锁读)不加锁(MVCC快照读)✅ 完全并发,读不阻塞写

🔐 三、S锁与X锁的兼容性矩阵

当前锁类型申请锁类型是否兼容
S锁S锁✅(可以同时读取)
S锁X锁❌(阻塞)
X锁S锁❌(阻塞)
X锁X锁❌(阻塞)

👉 结论:

  • 多个 S锁 可以共存。
  • X锁 只能独占。

📊 五、总结对比表

项目S锁(共享锁)X锁(排他锁)
允许读✅(自己可以)
允许写✅(自己可以)
可共存✅ 多个S锁可共存❌ 独占
与MVCC关系显式加锁读显式写操作
常见SQLSELECT ... LOCK IN SHARE MODEUPDATEDELETESELECT ... FOR UPDATE

💡 六、实际应用场景

场景推荐锁类型原因
需要读取后再判断是否更新SELECT ... FOR UPDATE确保数据不会被其他事务修改(加X锁)
仅需读取但希望防止被删除或修改SELECT ... LOCK IN SHARE MODE加S锁防止数据被改动
只想查(读一致性)普通 SELECT使用MVCC,性能最佳