并发控制是数据库理论里面最难的课题之一数据库
并发控制首先了解一下事务,transaction数据结构
定义以下,并发
其实transaction关键是,要知足ACID属性,分布式
左边的正式的定义,因为的intuitive的理解
其中可能Consistency比较难理解一下,其余都比较直观,对于单机数据库而言consistency其实不是个显著的问题,但对于分布式数据库这就是个主要问题性能
那么问题就是如何设计让Transaction知足ACID?flex
一种简单的方法就是,Strawman Systemui
串行执行保障consistency和isolate,整个库的copy保障atomicity,这个方法早期用在SQLlite中,它主要是用在嵌入式场景,访问量和数据量都很小atom
但这个方法的性能过低设计
下面就看看对ACID的各个属性,通常是如何设计来知足的3d
原子性问题,
最经常使用的方法是Log,Undo&Redo,这样若是事务abort,能够根据undo日志来回滚,达到原子性保证
还有种方法是Shadow Paging,也是MVCC,我修改的时候,把要修改的page复制一份去改,典型的使用是CouchDB
首先Consistency是逻辑的,什么意思?
就是和实现无关,作一笔转帐,两边的数据在逻辑上应该是对的,不管你底层是如何实现的,用何种数据结构
因此database consistency是指,作过的更新,在更新后,不管从什么地方角度去看,他都应该是同样的,好比在不一样的transaction中,不一样的client,不一样的。。。
对于单机数据库,这实际上是比较容易达成的
transaction consistency,是指应用层面的,外部的一致性,不光是数据库内部的,这种一致性须要应用本身去保障
隔离性,每一个transaction执行的时候,不会受到其余的transaction的干扰
由于咱们要提升数据库的性能,因此不可能让transaction串行执行,因此transaction必定是并发执行的,这样必定会存在interleave的问题
由于把transaction在物理上去作隔离必定是比较低效的,因此实际的作法都是让各个transaction interleave的执行,但其中要注意避免冲突,conflict
避免冲突通常都是要加锁,因此天然会有悲观和乐观锁的分别
这里先不谈怎么避免冲突
咱们先看下interleave执行会带来哪些问题?
对于这个例子,两个transaction,一个是转帐,一个是加利息
T1,T2,若是顺序执行的结果是同样的
这里注意,T1,T2自己谁先执行,这个是要应用控制的,对于数据库而言,不管谁先执行都是对的
那么能够看到interleave执行的结果多是good,也多是bad
若是判断是好是坏?这个很直觉,和串行执行结果同样就是好的,不然就是坏的
因此这里给出一堆概念,只是就是想说明,你interleave执行的结果必定要和串行执行同样
这样给transaction调度带来很大的flexible,由于只要知足serializable schedule,就能够任意的并发调度
Serializable Schedule的定义,一个Schedule和任意一个Serial Schedule是Equivalent的,即执行结果相同
那么咱们怎么判断一个sechdule是不是serializable?
咱们先看看,若是不知足serializable schedule,会发生什么?Conflict
冲突的双方必定是在不一样的transaction中,而且其中至少有一个是write操做
因此Conflict分为3种,read-read是不会冲突的
那么如今的思路,咱们只要去看看sechdule中是否存在这些conflict,若是不存在,咱们就能够认为这个sechdule是serializable
形式化的表达就是,若是S是和任意一个serial schedule冲突等价的,那么S就是conflict serializable;由于若是存在上面的冲突就不可能和serial schedule冲突等价
这里须要注意,咱们判断冲突的时候,通常只会看是否同时对一个object有读写,好比对于Unrepeatable Read,咱们不会看后面仍是不是有那个read,或者对于dirty reads,若是后面没有abort,也不会有问题;
因此这里是充分但没必要要条件,不知足conflict serializable,也不必定就获得错误的结果,可是知足,获得的结果必定是正确的
下面就要找一种方法,能够判断S是不是conflict serializable
咱们能够把任意不冲突的operation进行swap,看看最终能不能变成一个serial schedule
例子,
这个方法看着比较简单,但若是transaction比较多的话,会很难操做
因此须要一个更形式化的方法,称为依赖图
其实就是把冲突的依赖用线连起来,若是有环,说明是没法conflict serializable的
好比,你看右边的例子,是没法conflict serializable的
而example2,是能够conflict serializable,由于依赖图里面没有环
前面讲的都是Conflict Serialization
还有一种更为宽泛的叫作,View Serialization
定义很难理解,从例子上看,就是有些不符合conflict serialization的case,算出来结果也是对的,好比例子里面,由于是blind write,因此A的结果只会有最后一个write决定,因此这个schedule仍是能够强行等价于一个serial schedule的
View Serialization能够比Conflict Serialization有更多,更灵活的schedule,可是这个难于判断,很难实现
因此整体来讲,关系是这样的,越大调度越灵活,可是机制和判断越复杂