对数据库的丢失修改、脏读、不可重复读、虚读的理解

最近在复习准备找工作。复习到数据库中数据的不一致性,简单记录一下。
本文的例子来源于数据库系统概论第五版(王珊、萨师煊著)。

1. 例子

首先看一个简单的例子:
考虑飞机订票系统的一个活动序列:
(1)甲售票点(事务T1)读出某航班的机票余额A,设A=16.
(2)乙售票点(事务T2)读出同一航班的机票余额A,也为16.
(3)甲售票点卖出一张机票,修改余额A←A-1.所以A为15,把A写回数据库.
(4)乙售票点也卖出一张机票,修改余额A←A-1.所以A为15,把A写回数据库.
结果明明卖出两张机票,数据库中机票余额只减少1。
这种情况称为数据库的不一致性。这种不一致性是由事务的并发操作引起的。在并发的操作情况下,如果没有任何的并发控制机制,对事务T1、T2的两个事务的操作序列的调度是随机的。若按照上面的调度序列执行,T1事务的修改就被丢失了(丢失可以理解成为失效)。这是由于第4步中T2事务对A进行修改了,并且写回数据库覆盖了T1事务做出的修改。
并发操作带来的数据不一致性包括丢失修改、不可重复读和读“脏”数据。
课本原文中并没有提到虚读(也有人称为幻读)。

1.1 丢失修改

两个事务T1和T2读入同一数据并修改,T2提交的结果破坏了T1提交的结果,导致了T1的修改失效了。飞机订票的例子就属于此类。

1.2 脏读

读"脏"数据是指当事务T1修改某一数据时,事务T2读取同一数据后,T1由于某种原因撤销修改了,这时T1已修改过的数据恢复原值,而T2读到的数据是撤销修改之前的数据,那么此时T2的数据就与数据库中的数据不一致,则T2读到的数据就为"脏"数据,即不正确的数据。

1.3 不可重复读

不可重复读是指事务T1读取数据后,事务T2执行更新操作,使T1无法再现前一次读取结果。具体的,不可重复读包括三种情况:
(1)事务T1读取某一数据后,事务T2对其做了修改,当事务1再次读该数据时,得到与前一次不同的值。例如,T1读取B=100进行运算,T2读取同一数据B,对其进行修改后将B=200写回数据库。T1为了对读取值校对重读B,B已为200,与第一次读取值不一致。
(2)事务T1按一定条件从数据库中读取了某些数据记录后,事务T2删除了其中部分记录,当T1再次按相同条件读取数据时,发现某些记录神密地消失了。
(2)事务T1按一定条件从数据库中读取某些数据记录后,事务T2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。

1.4 虚读

事务A首先根据条件索引得到N条数据,然后事务B在N条之外删除或者增加了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了虚读。虚读貌似是MySql中的概念?
这么看的话,虚读不就是不可重复读中的第二、三种情况吗???

2. 数据库的隔离级别

产生上述四类数据不一致性的主要原因是并发操作破坏了事务的隔离性。并发控制就是要用正确的方式调度并发操作,使一个用户事务的执行不受其它事务的干扰,从而避免造成数据的不一致性。
有了以上的数据不一致性,那么数据库肯定要有相应的处理事务并行办法。
数据库的隔离级别越高,越能解决更多的数据不一致性问题。但是也是要牺牲的性能也逐渐递增。
以下事务隔离级别逐渐增加。

2.1 不支持事务

这种通常不讨论。

2.2 未提交读

顾名思义,就是在事务A未提交的时候,事务B可以进行读写。这种级别下,数据库会出现丢失修改、不可重复读、脏读和虚读等数据不一致性问题。

2.3 已提交读

顾名思义,就是只有在事务A已经提交的时候,事务B才可以进行读写。这种级别下,数据库不会出现在事务A执行过程中,B去读写的情况,那么B也不会出现脏读了。所以此级别可以避免脏读,但是不能避免可重复读以及虚读。

2.4 可重复读

顾名思义,这种级别可以避免不可重复读,也能避免脏读。但不能避免虚读。

2.5 可序列化

最高隔离级别。可以避免所有的数据不一致性问题。
个人理解:事务的隔离级别本质其实是底层使用了不同的封锁协议。因为封锁是实现并发控制的一个非常重要的技术。
对数据库的丢失修改、脏读、不可重复读、虚读的理解_第1张图片
图片来源于:https://blog.csdn.net/u013474436/article/details/53437220
补充:
基本的封锁类型有两种:排它锁(又称为X锁或者写锁)和共享锁(又称为S锁或者读锁)。
读锁之间可以共享,写锁既不能共享写锁也不能共享读锁。

你可能感兴趣的:(笔记,事务隔离级别,脏读,不可重复读,虚读)