近30年,DB只有一种广泛使用的串行化算法:两阶段加锁
2PL不是2PC
请注意,虽然两阶段锁定(2PL)听起来非常类似于两阶段提交(2PC),但是完全不同概念
之前我们知道,加锁可防止脏写:即若两个事务同时尝试写入同一对象,则锁可确保第二个写必须等第一个写完成事务(中止或提交)才能继续。
两阶段锁定类似,但锁的强制性更高。只要没有写入,就允许多个事务同时读取同一个对象。但对象只要有写,就得加锁独占访问:
- 若事务 A 已读某对象,此时B想写该对象,则必须等A提交或中止才能继续,这确保 B 不能在 A 执行过程的中间意外改变对象
- 若事务 A 已写某对象,此时 B 想读该对象,则 B 必须等 A 提交或中止才能继续,像图-1读取旧版本的对象在 2PL 下不可接受
2PL不仅在并发写互斥,读写之间也互斥。快照级别隔离是读写不互斥,这是 2PL 和快照隔离的关键区别。且因 2PL 提供串行化,可防止前文讨论的所有竞争条件,包括丢失更新和写倾斜。
3.2.1 实现原理
2PL已在:
- MySQL(InnoDB)和 SQL Server 实现可串行化
- DB2 中的可重复读
读与写的阻塞是通过为数据库中每个对象添加锁来实现的。锁可处于 共享模式或独占模式,使用如下:
- 若事务要读对象,则须先共享模式获取锁。允许多事务同时持有一个对象的共享锁。但若某事务已持有对象的独占锁,则其它事务必须等待
- 若事务要写对象,须以独占模式获取锁