如何设计事务系统
事务系统先解决运行时正确性:半成功、并发覆盖、读到中间状态。
边界:这一页先讲事务状态、锁、隔离和回滚。崩溃后的持久恢复交给下一页
WAL 和崩溃恢复。
BEGIN;
UPDATE table_page;
UPDATE index_page;
-- error here
ROLLBACK;
| 失败 | 长出的设计 |
| 表页改了,索引页没改。 | 事务边界:一组修改有统一命运。 |
| ROLLBACK 不知道改了什么。 | write set / undo record。 |
| 两个事务同时改同一行。 | 锁和冲突处理。 |
| 一个事务读到另一个事务中间状态。 | 隔离级别和可见性规则。 |
transaction:
tx_id
state -- active / committed / aborted
isolation -- read_committed / repeatable_read
write_set
locks_held
| 锁 | 保护什么 |
| shared lock | 读时防止被不兼容写破坏。 |
| exclusive lock | 写前独占 RID 或 page。 |
| 2PL | 增长阶段拿锁,收缩阶段释放锁,避免乱序可串行化问题。 |
| deadlock detection | 两个事务互等时,选择一个 abort。 |
| 操作 | Undo 需要什么 |
| INSERT | 记录新 RID,回滚时删除。 |
| UPDATE | 记录旧值,回滚时写回。 |
| DELETE | 记录被删 tuple,回滚时恢复。 |
| INDEX UPDATE | 记录旧 key、新 key,回滚时修索引。 |
| 实验 | 通过标准 |
| 事务更新三行后 abort。 | 三行和索引都恢复旧状态。 |
| 两个事务同时更新同一 RID。 | 一个等待、失败或死锁处理,不能静默覆盖。 |
| 读事务遇到写事务未提交数据。 | 按隔离级别决定等待、跳过或读旧版本。 |
| 两个事务互相等锁。 | 能检测或超时,并 abort 一个事务释放系统。 |
| commit 后释放锁。 | 其他事务能继续推进。 |
一句话:事务系统先保证运行时不写坏:事务有状态,修改有 undo,冲突有锁,死锁能处理,隔离规则清楚。崩溃恢复则交给 WAL。