数据库读写异常与隔离级别总结

本文详细探讨了关系型数据库中的读写异常现象,如脏读、不可重复读和幻读,以及写写数据异常的脏写和丢失更新。介绍了隔离级别如何解决这些问题,并特别提到了快照隔离技术及其局限性。最后,通过实例分析了语义约束引发的写偏序异常。
摘要由CSDN通过智能技术生成

1 概述

  在关系型数据库中,多个回话可以同时访问同一个数据库下同一个表中的同一行的数据,也就是说在同一时刻,该数据(行或元组)可以被多个会话进行操作(read or write),如果读写顺序的不同以及事务中A特性对事务结果的影响,这几种因素综合在一起,会存在对数据有不同的影响:

  • 读-读操作:如果多个回话只进行读操作,那么对于数据库中的数据来说,是没有任何影响的,即读-读操作不影响数据的一致性,读-读操作可以并发的执行。
  • 读-写操作:如果读-写操作都存在的话,因写在前读在后(脏读)、读在前写在后(不可重复读)、或者先读-后写-再读(幻读),可能到最后因数据写导致另一个读操作读到错误的数据。
  • 写-写操作:如果同时存在多个写操作,写-写操作会直接改变数据在同一时刻下的语义,这是不允许的,所以通常情况下写-写操作是不允许并发执行的。如果不对写-写操作进行控制,写-写并发就会出现异常现象。

1.1 三种读数据异常现象

  在事务的并发操作中可能会出现脏读,不可重复读,幻读等异常现象。下面通过事例一一阐述它们的概念与联系。

  • 脏读:指当一个事务正在访问数据,并且对数据进行了修改,而这种数据还没有提交到数据库中,这时,另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据还没有提交那么另外一个事务读取到的这个数据我们称之为脏数据。依据脏数据所做的操作肯能是不正确的。
  • 不可重复读:指在一个事务内,多次读同一数据。在这个事务还没有执行结束,另外一个事务也访问该同一数据,那么在第一个事务中的两次读取数据之间,由于第二个事务的修改第一个事务两次读到的数据可能是不一样的,这样就发生了在一个事物内两次连续读到的数据是不一样的,这种情况被称为是不可重复读。
  • 幻读:一个事务先后读取一个范围的记录,但两次读取的纪录数不同,我们称之为幻象读(两次执行同一条 select 语句会出现不同的结果,第二次读可能会多/少数据行)
    Note:脏读和不可重复读是以“行”为单位,而幻读是一个数据集(零行到多行)。

下一篇文章重点探讨 三种读数据异常现象

  为解决上述异常,数据库中通过隔离级别来实现,隔离级别从低到高分别为:读未提交(Read Uncommitted)、读已提交(Read committed)、可重复读(Repeatable read)、可串行化Serializable )。采用分级控制对脏读、不可重复读、幻读分别使用读已提交、可重复读、可串行化来实现。
在这里插入图片描述

1.2 两种写写数据异常现象

  在写并发情况下会引发如下数据异常现象,见表1:
在这里插入图片描述

  • 脏写现象:按照时间顺序,事务T1在t0时刻对row进行修改(更新),事务T2在t1时刻对row进行修改(更新),如果没有并发控制,T2对row的修改会生成新值,但是T1在t3时刻回滚使得T2对row的修改失效,而T1的语义是:T1自身对row的修改失效,这也把T2的修改值给回滚掉。对于事务T1而言,回滚掉的不是自己修改的数据,即事务T1上发生了脏写现象。
  • 丢失更新现象:按照时间顺序,事务T2在t1时刻对row进行了修改,事务T1在t2时刻对row进行了修改,如果没有并发控制,T1对row的修改会生成新值,但是T1在t3时刻提交使得T2对row的修改失效。对于事务T1而言,覆盖掉了不是自己修改的数据,即事务T1上引发了更新丢失。
      不管是读异常还是写异常,并发控制技术都要规避这些异常,保证数据在不同隔离界别下一致性不被破坏。

1.3 语义约束引发的数据异常现象

  我们知道在数据库并发控制技术中有一个大名鼎鼎的技术,成为快照隔离(Snapshot),这项技术能够解决了读写之间冲突,在保证数据不会产生前面提到的读异常和写异常的情况下,使得读不阻塞写,写不阻塞读,大大提高了并并发度。
  快照隔离并发控制技术的缺点是它并不能真正保证事务为“可串行化的”,即事务间的并发控制依旧会引发数据异常现象,但是这里的数据异常现象有别于前面提到的各种异常,其异常现象是“业务”引发的,即除了异常抽象的读写操作,数据间还应该满足一定语义,即约束(constraint)。在快照隔离并发控制技术下并发事务因不满足约束而发生的异常,成为写偏序(Write Skew),参见表2:
在这里插入图片描述

  • 两个事务引发的异常现象:按照时间顺序,T1事务在t0时刻读取在打电话的领导个数,T2事务在t1时刻读取在电话的领导个数。事务T1在t2时刻进行判断:如果在打电话的领导个数大于等于2人则请求Alice停止打电话。事务T2在t3时刻进行判断:如果在打电话的领导个数大于等于2人则请求Bob停止打电话。然后事务T1和T2分别提交事务。如果在这中并发情况下,允许事务T1和T2都提交成功,则t6时刻,Alice和Bob都停止打电话。如果事务串行执行事务,先执行事务T1后执行事务T2,Alice会停止打电话但Bob不会停止,这与前一种的结果不同。如果先执行事务T2后执行事务T1,Bob会停止打电话但Alice不会停止,这与前一种的结果不同。这表明前一种并发执行是非序列化的,而此时,事务T1、T2并发时违反了约束(约束为:如果同时打电话的人大于等于2人则请求Alice或Bob其中一个人停止打电话直到同时打电话的人数少2人)发生了写偏序异常。对于简单写偏序,可以用图2表示:
    在这里插入图片描述
  • 三个事务引发的异常现象:对于这种情况,后两个并发更新事务T2和T3是可串行化的且不存在任何异常,但是一个只读事务T1出现在某个时刻却可能正好造成问题。这个问题是:当事务T3提交时,T2处于活跃状态,这时事务T1启动要读取事务T2和T3涉及的数据(current_batch和receipts),这时事务T1的快照包括事务T3插入后的结果;但是,事务T2还没有提交,它的插入操作不包含在事务T1的快照中。在优先图图3中会造成一个环,说明这样的调度是非串行化的。
    在这里插入图片描述  如果在使用优先图表示时出现环则表明:调度是非串行化的。为解决这样的问题,通常采取回滚其中一个事务打破环的存在,即在事务提交时而不是在快照检查完整性约束,以避免出现不一致现象。

参考:https://wiki.postgresql.org/wiki/SSI#Read_Only-Transaction
该文为本人原创,转载请表明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值