[摘要] 数据库可以提供给多个用户共享数据信息资源,所以就必须对并发的事务进行控制,这种并发控制必须引入一些封锁协议以保证数据的完整性。本文针对数据库并发操作中可能产生的数据不一致性问题进行分析,并给出解决的方法。
[关键词] 数据库 并发控制 一致性 封锁 封锁协议
一、引言
目前主流的关系数据库通常都允许多个用户同时使用和共享,所以也都具有并发控制的机制,也就是控制数据库,防止多用户并发使用数据库时造成数据错误和程序运行错误,以保证数据的完整性。
二、事务与并发控制的概念
当多用户并发存取数据时,就会产生多个事务同时存取同一数据的情况,从而引起严重的数据错误和程序运行错误。
那么我们来看,什么是事务及并发控制呢?
事务就是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的很小的工作单位。例如,在sql语言中,定义事务的语句有三条:
begin transaction;
commit;
rollback;
其中的begin transaction是事务开始的标记,而以commit或者rollback结束,commit用于提交事务的所有操作,rollback则在事务运行过程中一旦发生了某种故障而使事务无法继续执行的时候,系统就将事务中对数据库的所有刚刚完成的操作全部撤消,滚动回到事务开始时的状态。
为了充分利用系统资源,使数据库的共享资源得以有效利用,必须可以使多个事务并行的执行,而数据库对并行执行的事务进行的控制就是并发控制。WWw.133229.CoM
三、事务进行并发操作可能引起的数据不一致问题
由于种种原因,都可能引起数据库的数据遭到破坏,比如多个事务在并行运行的时候,不同的事务的操作产生了交叉执行,或者,事务在运行过程中被强行停止或者中断。
因此,事务在进行并发操作的时候很可能引起数据的不一致,下面我们看一个具体的例子。例如飞机票的联网销售系统,如果有以下的操作序列:
1.甲售票处(设置为t1事务)读出某班次的机票剩余数a,设a=20
2.乙售票处(设置为t2事务)读出同班次的机票剩余数a,也是20
3.甲售票处(t1事务)卖出一张机票,修改剩余数减一(a←a-1),把a=19写回数据库中
4.乙售票处(t2事务)也卖出一张机票,修改剩余数减一(a←a-1),把a=19写回数据库中
从这些操作中,我们看到,乙售票处的修改数据覆盖了甲售票处修改的数据,实际发生了两张机票的销售,而数据库中却错误的存入19,少了一张。参看图1的情况。
这种情况是并发操作引起数据不一致的第一种情况,叫做丢失修改(lost update),第二种是不可重复读(non-repeatable read),第三种是读“脏”数据(dirty read)。
下边看第二种情况,不可重复读是指事务t1读数据以后,t2执行更新操作,就使t1无法再现原先读取的数据,得到与上一次不同的结果,例如图2。
读“脏”数据是指t1修改某数据并将其写回数据库,t2读取同一数据后,t1由于某种原因被撤消,t1执行回滚,恢复到原始的数据,t2就读取到了过程中的一个作废的数据,这个数据就是一种垃圾数据,称之为“脏”数据,也是不正确的。参看图3。
从以上例子我们看到,数据不一致性的主要原因就是并发操作没有对事务进行一定的隔离,所以,正确的调度应该使一个用户的事务不受到其他事务的干扰,从而避免数据的不一致性。
四、在并发控制中采用封锁协议解决数据的不一致性
并发控制的主要方法是封锁(locking)。就是要用正确的方式调度并发操作,使一个用户的事务在执行过程中不受其他事务的干扰,从而避免造成数据的不一致性。
封锁是使事务对它要操作的数据有一定的控制能力。封锁通常具有3个环节:第一个环节是申请加锁,即事务在操作前要对它将使用的数据提出加锁申请;第二个环节是获得锁,即当条件成熟时,系统允许事务对数据进行加锁,从而事务获得数据的控制权;第三个环节是释放锁,即完成操作后事务放弃数据的控制权。
基本的封锁类型有以下两种:
1.排它锁(exclusive locks,简称x锁)
排它锁也称为独占锁或写锁。一旦事务t对数据对象a加上排它锁(x锁),则只允许t读取和修改a,其他任何事务既不能读取和修改a,也不能再对a加任何类型的锁,直到t释放a上的锁为止。
2.共享锁(share locks,简称s锁)
共享锁又称读锁。如果事务t对数据对象a加上共享锁(s锁),其他事务只能再对a加s锁,不能加x锁,直到事务t释放a上的s锁为止。
在对数据进行加锁时,另外需要约定并执行一些规则和协议,其中包括何时申请锁,保持锁的时间以及何时释放等,这些规则就称为封锁协议(locking protocol),其总共分为以下三级:
(1)一级封锁协议。一级封锁协议是事务t在修改数据之前必须先对其加x锁,直到事务结束才释放。
(2)二级封锁协议。二级封锁协议是事务t对要修改数据必须先加x锁,直到事务结束才释放x锁;对要读取的数据必须先加s锁,读完后即可释放s锁。
(3)三级封锁协议。三级封锁协议是事务t在读取数据之前必须先对其加s锁,在要修改数据之前必须先对其加x锁,直到事务结束后才释放所有锁。
执行了封锁协议之后,就可以克服数据库操作中的数据不一致所引起的问题。
从图4的情况我们看到事务t1在执行过程中独自占用并加x锁,直到处理完之后再释放锁,t2虽然也需要使用,但是在封锁协议的约束之下,t2所要求的x锁就被拒绝,因此必须处于等待状态,直到t1释放之后,t2才获得使用的权利,这样就不会发生使用冲突,避免了数据的丢失。这里我们看到,此处实际上是执行了一级封锁协议。
下面我们看图5。
通过图5,能够清楚的看到,由于施行了封锁协议,使事务t1使用了共享锁占用a,b两块数据,这样t2需要加上的x锁就无法实现,(如果是s锁,虽然可以加上,但也不能够随便修改数据,只是读取一下数据。)当t1释放锁之后,t2就可以得到并使用锁了,这样读取的数据b仍然还是100,不影响a+b的结果,这就是可重复读取。因此我们看到,其实这里用的就是三级封锁协议。
参看图6,事务t1在对数据c修改之前,先加上了x锁,修改后写回数据库,这时t2请求在c上添加s锁,因为t1加了x锁,t2只好等待,当t1因为某种原因撤销了修改的数据后,c就恢复了原来的数据100,等t1释放x锁后t2获得c上的s锁,读到的还是c=100,因此避免了读出“脏”数据。这里使用的其实就是二级封锁协议。
通过以上内容,数据库由于采用一定的封锁协议避免了数据的不一致性问题,这使得数据库的并发控制有效而且有益,从而使得多项事务可以并行的操作数据库的共享资源了。这就是数据库合理的进行调度,避免了冲突,避免了数据的不一致。
参考文献:
[1]苗雪兰:数据库系统原理及应用教程[m].北京:机械工业出版社,2004
[2](美)mary pyefinch著:希望图书创作室译[m].sql数据库开发从入门到精通[m].北京希望电子出版社,2000
[3]丁宝康董健全:数据库使用教程[m].北京:清华大学出版社,2001