当同一数据库系统中有多个事务并发运行时,如果不加以适当控制,可能产生数据的不一致性。
[例1]并发取款操作。假设存款余额R=1000元,甲事务T1取走存款100元,乙事务T2取走存款200元,如果正常操作,即甲事务T1执行完毕再执行乙事务T2,存款余额更新后应该是700元。但是如果按照如下顺序操作,则会有不同的结果:
甲事务T1读取存款余额R =1000元;
乙事务T2读取存款余额R =1000元;
甲事务T1取走存款100元,修改存款余额R =R -100=900,把R =900写回到数据库;
乙事务T2取走存款200元,修改存款余额R =R -200=800,把R =800写回到数据库。
结果两个事务共取走存款300元,而数据库中的存款却只少了200元。
得到这种错误的结果是由甲乙两个事务并发操作引起的,数据库的并发操作导致的数据库不一致性主要有以下三种:
当两个事务T1和T2读入同一数据做修改,并发执行时, T2把T1或T1把T2的修改结果覆盖掉, 造成了数据的丢失更新问题,导致数据的不一致。
仍以例6.1中的操作为例进行分析。
在表5.5中,数据库中R的初值是1000,事务T1包含三个操作:读入R初值(FIND R);计算(R=R-100);更新R(UPDATE R)。
事务T2也包含三个操作:FIND R;计算(R=R-200);UPDATE R。
如果事务T1和T2顺序执行,则更新后,R的值是700。但如果T1和T2按照表5.5所示的并发执行,R的值是800,得到错误的结果,原因在于在t7时刻丢失了T1对数据库的更新操作。
因此,这个并发操作不正确。
表5.5 丢失更新问题
2.污读(Dirty Read)
事务T1更新了数据R,事务T2读取了更新后的数据R,事务T1由于某种原因被撤消,修改无效,数据R恢复原值。事务T2得到的数据与数据库的内容不一致,这种情况称为“污读”。
在表5.6中,事务T1把R的值改为900,但此时尚未做COMMIT操作,事务T2将修改过的值900读出来,之后事务T1执行ROLLBACK操作,R的值恢复为1000,而事务T2将仍在使用已被撤消了的R值900。
原因在于在t4时刻事务T2读取了T1未提交的更新操作结果,这种值是不稳定的,在事务T1结束前随时可能执行ROLLBACK操作。
对于这些未提交的随后又被撤消的更新数据称为“脏数据”。
比如,这里事务T2在t2时刻读取的就是“脏数据”。
表5.6 污读问题
3.不可重读(Unrepeatable Read)
事务T1读取了数据R,事务T2读取并更新了数据R,当事务T1再读取数据R以进行核对时,得到的两次读取值不一致,这种情况称为“不可重读”。
在表5.7中,在t0时刻事务T1读取R的值为1000,但事务T2在t4时刻将R的值更新为为800。所以T1所使用的值已经与开始读取的值不一致。
表5.7 不可重读问题