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 UNCOMMITTED | 
9 | 
能读到未提交数据(脏读) | 
| READ COMMITTED | 
10 | 
只能读到已提交数据 | 
| REPEATABLE READ(默认) | 
10 | 
使用快照读,读到的是事务开始时的版本 | 
| SERIALIZABLE | 
10 | 
加锁读,阻塞直到事务A提交或回滚 | 
2.数据库s锁与x锁
🧩 一、S锁与X锁的基本定义
| 锁类型 | 
全称 | 
英文名称 | 
作用 | 
| S锁 | 
共享锁 | 
Shared Lock | 
允许多个事务同时读取同一行,但不允许修改 | 
| X锁 | 
排他锁 | 
Exclusive Lock | 
只允许一个事务对该行进行读写,其他事务不能再加任何锁 | 
🧠 二、加锁后的行为差异
| 操作类型 | 
需要的锁类型 | 
是否允许并发 | 
SELECT ... LOCK IN SHARE MODE | 
S锁 | 
✅ 允许其他事务也加S锁(共享读) ❌ 不允许X锁(写) | 
SELECT ... FOR UPDATE | 
X锁 | 
❌ 其他事务不能加任何锁(读写都阻塞) | 
UPDATE / DELETE / INSERT | 
X锁 | 
❌ 独占该行 | 
普通 SELECT(无锁读) | 
不加锁(MVCC快照读) | 
✅ 完全并发,读不阻塞写 | 
🔐 三、S锁与X锁的兼容性矩阵
| 当前锁类型 | 
申请锁类型 | 
是否兼容 | 
| S锁 | 
S锁 | 
✅(可以同时读取) | 
| S锁 | 
X锁 | 
❌(阻塞) | 
| X锁 | 
S锁 | 
❌(阻塞) | 
| X锁 | 
X锁 | 
❌(阻塞) | 
👉 结论:
📊 五、总结对比表
| 项目 | 
S锁(共享锁) | 
X锁(排他锁) | 
| 允许读 | 
✅ | 
✅(自己可以) | 
| 允许写 | 
❌ | 
✅(自己可以) | 
| 可共存 | 
✅ 多个S锁可共存 | 
❌ 独占 | 
| 与MVCC关系 | 
显式加锁读 | 
显式写操作 | 
| 常见SQL | 
SELECT ... LOCK IN SHARE MODE | 
UPDATE、DELETE、SELECT ... FOR UPDATE | 
💡 六、实际应用场景
| 场景 | 
推荐锁类型 | 
原因 | 
| 需要读取后再判断是否更新 | 
SELECT ... FOR UPDATE | 
确保数据不会被其他事务修改(加X锁) | 
| 仅需读取但希望防止被删除或修改 | 
SELECT ... LOCK IN SHARE MODE | 
加S锁防止数据被改动 | 
| 只想查(读一致性) | 
普通 SELECT | 
使用MVCC,性能最佳 |