事务不是给 SQL 加一个注解,而是把必须共同成功的一组状态变化划进边界。隔离级别控制并发事务互相可见的程度;级别越高不等于业务一定越正确。
Table of contents
Open Table of contents
用转账理解 ACID
- Atomicity,原子性:扣款与入账全部成功或全部回滚。
- Consistency,一致性:事务前后都满足余额非负、总额守恒等约束。数据库约束和业务规则共同承担它。
- Isolation,隔离性:并发转账不能互相读到不允许看到的中间状态。
- Durability,持久性:提交成功后,即使进程崩溃也能恢复结果。
ACID 不是四个独立开关。Undo、Redo、锁、MVCC、刷盘策略和应用事务边界共同实现这些性质。
四种隔离级别
| 级别 | 典型可见性 |
|---|---|
| READ UNCOMMITTED | 可能读到未提交数据 |
| READ COMMITTED | 每条语句看到开始时已提交的快照 |
| REPEATABLE READ | 同一事务的普通一致性读通常复用快照 |
| SERIALIZABLE | 约束最强,并发与等待成本也通常更高 |
MySQL InnoDB 默认是 REPEATABLE READ。MySQL 的具体行为不能只按教科书现象表推断:普通快照读、SELECT ... FOR UPDATE 锁定读、更新语句采用的机制不同。
业务正确性仍要显式设计
两个请求都先读库存 1,再各自减 1,单靠“可重复读”不必然避免丢失更新。可以用条件更新:
UPDATE inventory
SET available = available - 1
WHERE sku_id = ? AND available > 0;
然后检查影响行数。也可使用 FOR UPDATE 悲观锁或版本号乐观锁。实验室的 updateStatus 展示了版本号方案。
事务要短:不要在持锁事务中调用远程服务、等待人工输入或处理大文件。失败时回滚整个业务操作,并让重试具备幂等性。
参考 InnoDB 隔离级别。
下一步
继续阅读06-10 InnoDB 锁、死锁与锁等待,观察事务竞争时数据库究竟锁住了什么。