Data consistent && transaction && isolation level

数据一致性

数据一致性是指在并发访问数据库的时候,数据需要保持一致,那么什么样算不一致呢? 看一看反面的例子,就明白了。

不一致的情况有三种,脏读,不可重复读和幻影读。

假设现在有一个表,如下:

 1 SQL> select * from t;
 2 
 3         ID ENAME                          JOB                                SAL
 4 ---------- ------------------------------ --------------------------- ----------
 5          1 SMITH                          CLERK                              800
 6          2 ALLEN                          SALESMAN                          1600
 7          3 WARD                           SALESMAN                          1250
 8          4 JONES                          MANAGER                              1
 9          5 MARTIN                         SALESMAN                          1250
10          6 BLAKE                          MANAGER                           2850
11          7 CLARK                          MANAGER                           2450
12          8 SCOTT                          ANALYST                           3000
13          9 KING                           PRESIDENT                         5000
14         10 TURNER                         SALESMAN                          1500
15         11 ADAMS                          CLERK                             1100
16         12 JAMES                          CLERK                              950
17         13 FORD                           ANALYST                          99999
18         14 MILLER                         CLERK                             9999

 我们采用例子来逐个说明:

脏读

假设 10:00的时候,manager对第一个员工SMITH的工资做出了更改,由800变成了1000元。 但是manager还没有把这条更改提交到数据库中,也许他还在犹豫,不确定,但不管怎样,他没有commit这条数据。

这时候,10:01,smith来到系统查询自己的sal,发现是1000. 那么着就是脏读。  脏读就是读取到了别人修改过但是没有commit的数据。

不可重复读

假设这个表非常大,用户A在查询表的信息,他10:00开始查询,这时他查到SMITH的工资为800,但是10:01的时候用户B把smith的工资改成了1000,把最后一个人Miller的 工资改成了9888。并且commit了更改。那么A会发现Miller的工资是9888,但实际这是不准确的,因为这个9888是后改的,并不是10:00时刻的工资。 另外如果A在transaction内再次读取表会发现smith的工资跟以前也不一样了。 这就叫不可重复读。

其实还有一种不可重复读,我们可以把它定义成不可重复度(A)

不可重复度(A)

假设用户A在10:00的时候读取了表的信息,并且打算根据得到的这些信息对表进行更改。 比如根据Id进行更改表。但是用户A读取表花了2分钟,在10:02才 开始更改。但是在这之前,在正式开始修改之前,有人把所有的工资都置成了100.那么这时候用户A去修改表的时候就会出错,因为他在基于之前的信息修改表,但是之前的信息不准确。

其实这两个不可重复读都是一样的,都是之前读到的信息现在不存在了。 不同之处只是在于前一个只是要读,而后一个要读完之后再修改。 我们把它们单独列出来讨论的原因是因为oracle 对这两个问题的解决方式不一样。

幻影读

假设用户A在10:00开始读取数据,10:01的时候用户B在表的结尾加了一条数据,10:02的时候用户A读到了表的结尾,那么如果用户A读取到了这条新数据,那么这就是幻影读,因为A读的应该是10:00的数据,那时候没有这个数据。

隔离级别

SQL标准中定义了四种数据一致性级别,也就是我们说的隔离级别。

隔离级别                    dirty read  unrepeatable read

Phantom read

read uncommi y   y y
read commited n y y
repeatable n n y
serialization n n n

对于这些数据一致性级别,要知道的是存在未必合理。也就是说这些隔离级别其实是针对不同业务需求的。 看你自己的需求而定。 对于oracle来说,默认的数据一致性级别是read committed。同时oracle还支持 seialization 和 read only(这个不在sql标准里面)。 我们只讨论oracle read commite 。另外两个,seialization和sql标准是一样的,read only是oracle自己定义的,顾名思义不可以更改,自然没有数据一致性问题。

oracle  read committed

oracle 的read commited和sql 标准的read commited是一样的。 所以oracle可以避免脏读。 但是对于unrepeatable和phantom读是怎么处理的呢? oracle采用scn读的方式来读取数据,也就是说,数据不但要被commit了,而且还要符合scn读的标准才可以被读到。所谓SCN读就是说,oracle在时刻a读取一个表,在读的过程中如果有一个记录被修改了那么它的scn就会变大,oracle就会比较a时刻的scn和该记录的scn,然后知道这条记录是后改的,所以oracle就会去读这个记录的一个之前映像。这样oracle就解决了 第一种unrepeatable read 的问题。

对于第二种,unrepeatable read,oracle采取 for update的方式来解决,也就是说你在读的同时不让别人修改这个表,这样你想更改的时候使用的记录自然正确。但是这种方式会导致并发性能低下,你可以采取另外一种方式,就是读的时把所有的column都读出来,update的时候也用所有的column,这样不会影响并发,也不会覆盖别人的修改。

原文地址:https://www.cnblogs.com/kramer/p/2986695.html