什么是事务并发
- I/O与CPU等可以并行交叉运行
- 并发执行的优点
改善系统的资源利用率
减少短事务的等待时间
事务并发引起的问题
- 读脏数据
脏数据(dirty data)是对未提交事务所写数据的统称。
若脏读就造成了数据库的不一致状态,应严格禁止。
若脏读带来的影响足够小,偶尔可读一次脏数据,它可以提高并发性,减少事务的等待时间 - 不可重复读(unrepeatable read)
事务T1的两次读取数据之间,其它事务修改了它要读取的数据,以致两次读到的值不同
在事务串行执行时,不会出现此现象 - 丢失更新(lost update)
由两个事务对同一数据并发地写入引起
可串行化
事务在运行中不受其它事务干扰的方法(保持隔离性):
串行:
每个事务依次顺序执行
并行但控制:
事务之间并发执行,DBMS调整事务的调度,使其运行结果与一次只执行一个事务的结果相同
可串行化调度
调度是可串行化的:多个事务交叉调度的结果与某一个串行调度的结果相同
DBMS认为事务串行调度的结果保持了数据库的一致性,都是正确的
一个调度如果是可串行化的,系统认为其调度是一个正确的调度,保持了数据库的一致性
冲突可串行化
若一个调度冲突等价于一个串行调度,则该调度是冲突可串行化的。
例如
调度S= R1(A) W1(A) R2(A) W2(A) R1(B) W1(B) R2(B) W2(B)
R1(B)与W2(A)指令不冲突,可以交换执行顺序;
R1(B)与R2(A)指令不冲突,可以交换执行顺序;
W1(B)与W2(A)指令不冲突,可以交换执行顺序;
W1(B)与R2(A)指令不冲突,可以交换执行顺序。
调度S’= R1(A) W1(A) R1(B) W1(B) R2(A) W2(A) R2(B) W2(B)
调度S’是一个串行调度。
调度S等价于串行调度S’,是冲突可串行化的。
视图等价
对同一事务集,如果两个调度S1和S2在任何时候都保证每个事务读取相同的值,写入数据库的最终状态也是一样的,则称调度S1和S2视图等价。
如果某个调度视图等价于一个串行调度,则称这个调度是视图可串行化的
如果调度是冲突可串行化的,则该调度一定是视图可串行化的。但反过来未必成立。
举例
设调度S1= R1(A) W3(A) R2(B) W1(B)
经过非冲突调整,S2 = R2(B) R1(A) W1(B) W3(A)
调度S1和调度S2是冲突等价的。
又因为调度S2为一串行调度,因此调度S1是冲突可串行化的。
对于调度S1和S2,事务T1读取的A、事务T2读取的B都是数据库的初始值;数据库最终的A、B值都是由事务T3和T1写入的。
因此,调度S1和S2是视图可串行化的。
可串行化的判定
判定一个调度是否是冲突可串行化的,可以使用前驱图(precedence graph)
若前驱图中存在环,则表示调度S是不可串行化的。
反之,若前驱图中不存在环,表示调度S是冲突可串行化的,可用拓扑排序得到调度S 的一个等价的串行调度。
基于锁的管理
锁相容性
- 锁的类型
共享锁(S锁):如果事务Ti申请到数据项Q 的共享锁,则Ti可以读数据项Q,但不能写Q。
排它锁(X锁):如果事务Ti申请到数据项Q 的排它锁,则Ti可以读数据项Q,也可以写Q。
申请锁
T1,T2:更新后立即释放锁,可能脏读。
T3,T4:事务的最后释放锁,避免脏读和确保可串行性。但降低并发度
T5,T6:相互等待出现死锁
2P协议
两段锁协议(two-phase locking protocol,2PL)是指所有事务分两个阶段提出加锁和解锁申请:
增长阶段(growing phase):在对任何数据进行读、写操作之前,首先申请并获得该数据的封锁;
收缩阶段(shrinking phase):在释放一个封锁后,事务不再申请和获得其它的任何封锁。
两段锁协议是保证冲突可串行化的充分条件,但该协议不保证不发生死锁。
严格2P协议
2p协议存在级联回滚现象
严格两阶段锁
- 除要求满足两段锁协议规定外,还要求事务的排它锁必须在事务提交之后释放。
- 解决级联回滚问题
- 避免了脏读和丢失修改的问题。
强两阶段锁
除要求满足两段锁协议规定外,还要求事务的所有锁都必须在事务提交之后释放。
进一步解决数据项不能重复读的问题
更新锁
锁的升级有可能使得出现死锁的概率加大
更新锁只允许事务读取数据项而不能修改数据项
系统允许更新锁升级,而不允许共享锁升级