首先介绍三类并发问题:
1.脏读:一个事务读到另一个事务未提交的更新数据(A和B事务并发执行,B事务执行更新后,A事务查询B事务没有提交的数据,B事务回滚,则A事务得到的数据不是数据库中的真实数据。也就是脏数据,即和数据库中不一致的数据)。 2.不可重复读:一个事务读到另一个事务已提交的更新数据(A和B事务并发执行,A事务查询数据,然后B事务更新该数据,A再次查询该数据时,发现该数据变化了)。 3.虚读(幻读):一个事务读到另一个事务已提交的新插入的数据(A和B事务并发执行,A事务查询数据,B事务插入或者删除数据,A事务再次查询发现结果集中有以前没有的数据或者以前有的数据消失了)。
相应的有四种事务隔离级别供用户选用:
脏读 | 不可重复读 | 幻读 |
---|---|---|
读未提交 | Y | Y |
读提交 | N | Y |
可重复读 | N | N |
串行化 | N | N |
下面介绍两阶段封锁协议(2PL)。2PL可以使事务的隔离级别达到可串行化。2PL要求每个事务分两个阶段提出加锁和解锁申请:
1.增长阶段:事务可以获得锁,但是不能释放锁 2.缩减阶段:事务可以释放锁,但是不能获得锁
一开始,事务处于增长阶段,事务根据需要获得锁。一旦该事务释放锁,就进入缩减阶段,不能再发出加锁请求。我们可以证明2PL协议保证冲突可串行化。对于任何事务,在调度中该事务获得其最后的加锁位置(增长阶段结束点)称为事务的封锁点。这样,多个事务可以根据它们的封锁点进行排序,实际上,这个顺序就是事务的一个可串行化顺序。但是,2PL不保证不发生死锁,例如:
T3 | T4 |
---|---|
lock-X(B)read(B)B:=B-50write(B) | |
lock-S(A)read(A)lock-S(B) | |
lock-X(A) |
*其中lock-X表示排它锁,lock-S表示共享锁此时,事务T3等待T4释放A上的共享锁,T4等待T3释放B上的排他锁,发生死锁。死锁的解决方法有两种,一种是预防,一种是检测与恢复。这里采用第二种方法,锁的等待关系可以用有向图来表示,如T3->T4表示T3等待T4释放锁。转化为图后,如果有向图中有环,则有死锁。这里使用NyaDB的死锁检测与恢复方法:
1.设置一个时间戳stamp = 0; 2.为每个点设置一个”访问戳”, visStamp, 初始化为-1; 3.任意选择一个visStamp为-1的点, 设它为s; 4.stamp++; 5.从s开始遍历, 对每个遍历到的点u进行下面的判断: 6.===> 如果visStamp[u] == -1, 则visStamp[u] = stamp, 继续遍历; 7.===> 如果visStamp[u] != -1 and visStamp[u] < stamp, 跳过点u, 即不以它为节点继续向下遍历; 8.===> 如果visStamp[u] == stamp, 则有环, 结束算法; 9.当从s开始遍历完且并没发行环, 重复3), 直到没有visStamp为-1的点. 10.当整个算法结束时, 都没发现环, 则无环.
将等待图维护在内存中, 每当出现等待时, 则向图中加入一条边。 每向图中加入一条边, 便进行一次死锁检测。 如果加入某条边后检测到了死锁, 则撤销加入这条边的事务。
考虑如下图的事务调度:
T5 | T6 | T7 |
---|---|---|
lock-X(A)read(A)lock-S(B)read(B)write(A)unlock(A) | ||
lock-X(A)read(A)write(A)unlock(A) | ||
lock-S(A)read(A) |
如果在事务T7的read(A)步骤之后事务T5发生故障需要回滚,此时虽然T6和T7并没有发生故障,但是因为这两个事务中有一部分命令是在事务T5开始到故障点之间执行的,所以也需要回滚,这就导致了级联回滚。级联回滚需要撤销大量的工作,这是数据库系统不希望见到的。可以通过将2PL协议变为严格2PL协议来避免级联回滚。严格2PL协议不仅要求封锁是两阶段的,还要求事务持有的所有排他锁必须在事务提交之后才能释放。这个要求保证了未提交事务所写的任何数据在该事务提交之前均以排他锁方式加锁,防止了其他事务读取这些数据。应用严格2PL协议的级联回滚事务调度变成了下图的样子,防止了级联回滚的出现:
T5 | T6 | T7 |
---|---|---|
T5 beginslock-X(A)read(A)lock-S(B)read(B)write(A)unlock(A)…………release all lockT5 is finished | ||
T6 beginslock-X(A)read(A)write(A)unlock(A)…………release all lockT6 is finished | ||
T7 beginslock-S(A)read(A)…………release all lockT7 is finished |
1.NyaDB的技术文档:https://qw4990.gitbooks.io/nyadb/content/chapter4.html2.数据库系统概念(原书第5版) 第16章 并发控制
新闻热点
疑难解答