冲突
调度中的一对连续操作,如果满足,调换位置后,涉及的事务至少有一个事务的行为会发生改变,造成调度结果的变化
所以说,有冲突的两个操作是不可以交换次序的。
那如何直观地理解两个操作是否会产生冲突呢?
T1 | T2 |
---|---|
READ A | |
READ B | |
A=A-10 | |
B=B-20 | |
WRITE A | |
WRITE B | |
READ B | |
READ C | |
B=B+10 | |
C=C+20 | |
WRITE B | |
WRITE C |
不同事务对于同一数据元素的不同操作,调换次序比如,将上方表格调整为:
T1 | T2 |
---|---|
READ A | |
READ B | |
A=A-10 | |
B=B-20 | |
WRITE A | |
READ B | |
WRITE B | |
READ C | |
B=B+10 | |
C=C+20 | |
WRITE B | |
WRITE C |
结果就会差生不一致,调整前,写入A
为A-10
,B
先写入B-20
,再修改成B-10
,C
写入为C+20
;调整后,写入A
为A-10
,B
先写入B-20
,然而在写入之前读了B
,还是B
本身,最后B
的值被覆盖成B+10
,C
写入仍然为C+20
。
总的来说,冲突发生的情况可以归纳为:
- 不同事务对同一元素的两个写操作是冲突的
- 不同事务对同一元素的一读一写操作是冲突的
什么叫冲突可串行化?
一个并行调度经过不停地交换相邻的不产生冲突的操作,可形成一个串行调度。
T1 | R(A) | W(A) | R(B) | W(B) | ||||
---|---|---|---|---|---|---|---|---|
T2 | R(A) | W(A) | R(B) | W(B) |
swap
T1 | R(A) | W(A) | R(B) | W(B) | ||||
---|---|---|---|---|---|---|---|---|
T2 | R(A) | W(A) | R(B) | W(B) |
swap
T1 | R(A) | W(A) | R(B) | W(B) | ||||
---|---|---|---|---|---|---|---|---|
T2 | R(A) | W(A) | R(B) | W(B) |
swap
T1 | R(A) | W(A) | R(B) | W(B) | ||||
---|---|---|---|---|---|---|---|---|
T2 | R(A) | W(A) | R(B) | W(B) |
如何验证是否冲突可串行化?
PRECEDENCE GRAPH!!!
结点代表事务,如果Ti与Tj的一个操作发生冲突,且Ti在Tj之前执行,则连线从Ti指向Tj。如果该有向图不成环,则称为冲突可串行化。(可以不挨着,因为可以交换相邻不产生冲突的元素!)
基于锁的并发控制
为了在冲突不可串行化的调度中获得可串行化调度,引入锁协议。
-
如果事务是一个操作来操作
X
: 在Read X
之前获得对X
的读锁,在Write X
之前获得对X
的写锁,相对应解锁。 -
如果事务有几个操作来操作
X
: 仅在X上获得一个适当的锁,写锁优先级更高,如果所有操作都是读操作,则为读锁;只要众多操作中其中之一是写操作,则为写操作,在所有操作执行完成之后解锁。
控制并发的手段之一,每一数据元素都有唯一的锁;每一事务读写数据元素前,要获得锁;如果被其他事务持有该元素的锁,则需要等待;事务处理完后需要释放锁。
事务调度器对所有事务的操作产生一个读写操作序列(调度),保证事务的一致性。
调度器可以利用锁来保证冲突可串行性。
读锁写锁区别
排他锁X: 只有一个事务(也就是被加上锁的事务)能对某一个数据元素读、写,其他任何事务都不能对该数据元素读、写
共享锁S:所有事务都可以对某一个数据元素读,但不可以写
加锁,解锁的时机
0级协议(0-LP)有写要求的数据对象A加排他锁,不在访问后即可解锁,可防止丢失修改,但允许脏读,允许重复读错误。
1级协议(1-LP)有写要求的数据对象A加排他锁,事务提交时刻解锁,可以防止丢失修改,可以恢复,防止脏读,但允许重复读错误。
2级协议(2-LP)有写要求的数据对象A加排他锁,事务提交时刻解锁;有读要求的数据对象B加共享锁,不在访问后即可解锁,可以防止丢失修改,可以恢复,防止脏读,不允许重复读错误。
3级协议(3-LP)有写要求的数据对象A加排他锁,事务提交时刻解锁;有读要求的数据对象B加共享锁,事务提交时解锁,防止所有不一致性,但是并发度最低。
两段封锁协议
如何判断一个并发调度是否正确?当且仅当在这个并发调度下所得到的新数据库结果与分别串行地运行这些事务所得的新数据库完全一致,则说调度是正确的。如何产生一个冲突可串行化调度?
两端锁协议
读写数据前要获得锁,每个事务中所有锁请求先于任何一个解锁请求,也就是加锁解锁严格分为两阶段,加锁段,解锁段,加锁段不能有解锁操作,解锁段不能有加锁操作。