事务的并发控制
如何判断是否等效
冲突操作
- 不同的操作事务
- 不同的任务操作的同样的数据,并且至少一个是写
冲突类型
- RW冲突:事务第一次读到第二次读的数据不同(其实就是不可重复读)
- WR冲突:T1先写,但是未提交T2读取,导致读取到了脏数据
- WW冲突:丢失修改,两个写同步进行,导致某些写被覆盖而丢失
事务冲突的执行调整
对于事务之间并行执行的冲突,正常来讲就是通过一些调整,使其转换成为按照时间顺序的事务串行,达到并行的目的。但是有些事务调整之后也是冲突的,所以说并行也只是能够并行的执行不冲突的语句,对于冲突的语句还是需要等待提交来执行。
依赖图表示事务冲突
上文中的调整方法开销太大,并且算法不直观。可以通过图表示,箭头代表冲突依赖,起点需要在终点之前执行,判断方式:
- 图中有环就不能够串行等价
- 如果是可以拓扑解开,就代表可以按照这种拓扑顺序并发执行,等效于串行。
> 依赖图的局限性在于某些特殊的情况是可以等效串行化,但是依赖图是有环冲突的。例如下图中实际上就是T3最后W(A),T1,T2随意执行都可以,所以也是可以等效串行化的
分析
串行化 < 等效串行化 < 观察等效串行化
总结
两阶段锁
上一节讲到了串行化等效,但是这种判断需要事务中语句的执行时间来判断,也就是说其实事务是已经执行完提交了才判断的,那就算是错误的也提交了,只能回滚之类的处理
解决方案:加锁
锁的类型
lock是用来的数据,数据库抽象程度上锁,而latches是从物理层面,B+树节点上锁。
lock中的锁可以分成S(共享),X(排他)锁
问题
就算是遵循操作数据需要加锁,但是加了锁也并不是可串行化的。即图中还是冲突的,除非一直锁A,但是这样就没有意义了。
二阶段锁方案
分成加锁阶段和解锁阶段,也就是两个阶段都只能纯粹的其中一种。
例如下图中需要等到加锁阶段结束之后才能够解锁,这样就能保证冲突的等效串行化。依赖图中也绝对没有环。