最详细(准确)的事务隔离级的理解,主要是看懂那个模型

版权声明:本文为博主原创文章,请尊重劳动成果,转载注明一下出处。 https://blog.csdn.net/zq1994520/article/details/82667231

先厚颜无耻copy个东西:

一、copy部分:

1、 原文连接 https://blog.csdn.net/csdnxingyuntian/article/details/57081233

事务就是一组原子性的SQL查询,或者说一个独立的工作单元。如果数据库引擎能够成功地对数据应用该组查询的全部语句,那么久执行该组查询。如果其中任何一条语句因为崩溃或其他原因无法执行,那么所有语句都不会执行。也就是说,事务内的语句,要么全部执行成功,要么全部执行失败。

事务的四大特性(ACID):

1.原子性(atomicity):一个事务必须视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性。

2.一致性(consistency):数据库总数从一个一致性的状态转换到另一个一致性的状态。

3.隔离性(isolation):一个事务所做的修改在最终提交以前,对其他事务是不可见的。

4.持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。

数据库事务的隔离级别有4种,由低到高分别为Read uncommitted 、Read committed 、Repeatable read 、Serializable 。而且,在事务的并发操作中可能会出现。下面通过事例一一阐述它们的概念与联系。

我理解的数据库里面加锁对应的数据结构模型:

一份数据他们两个把数据分为若干份数据,一个是给写用(排他锁),其它的是给读用(共享锁)。

读用的数据把数据按照时间节点分为不同的部分,把时间节点和对应的session绑定一起。

写数据通过排他锁,让所有事务共享一份数据,对这份数据排队进行写操作。

所以不管怎么做,如果不用范围锁(和读写锁不一样的,性能耗费很大),总会又“幻读”的情况。

注:

不可重复读:T1事务两次读;T2对数据修改,添加,删除。T2的对数据的操作T1是查询查询到了。

幻读:T1事务一次查询,一次数据更新或者删除;T2对数据添加操作T1后面的数据更新察觉到了,导致事务T1程序逻辑出现问题,先查询得到的查询条数和最后更新数据影响的条数不能相对应。

2、原文:https://www.cnblogs.com/sushu-yaya/p/6944287.html

脏读,不可重复读,幻读、丢失更新的详细解释:(上面原文对于“幻读”解释有些问题)

1.脏读(Dirty Read)——一个事务读取到了另外一个事务没有提交的数据。

详细解释:当一个事务正在访问数据并且对数据进行了修改,而这种修改还没有提交到数据库中,这时另外一个事务也访问这个数据,然后使用了这个数据。因为这个数据是还没有提交的数据,那么另外一个事务读到的这个数据是脏数据,依据脏数据所做的操作可能是不正确的。

事务T1:更新一条数据
          -->事务T2:读取事务T1更新的记录
 事务T1:调用commit进行提交
 此时事务T2读取到的数据是保存在数据库内存中的数据,称为脏数据,这个过程称为脏读。

脏读发生在一个事务A读取了被另一个事务B修改,但是还未提交的数据。假如B回退,则事务A读取的是无效的数据。这跟不可重复读类似,但是第二个事务不需要执行提交。

解决脏读问题:修改时加排他锁,直到事务提交后才释放,读取时加共享锁,读取完释放事务1读取数据时加上共享锁后(这样在事务1读取数据的过程中,其他事务就不会修改该数据),不允许任何事务操作该数据,只能读取,之后1如果有更新操作,那么会转换为排他锁,其他事务更无权参与进来读写,这样就防止了脏读问题。但是当事务1读取数据过程中,有可能其他事务也读取了该数据,读取完毕后共享锁释放,此时事务1修改数据,修改完毕提交事务,其他事务再次读取数据时候发现数据不一致,就会出现不可重复读问题,所以这样不能够避免不可重复读问题。(这儿补充一下,排他锁是独占锁,而共享锁是可以让多个对象同时获取的,共享锁的功能就是在读取的时候不让数据被修改。可以把上面的描述简单的理解成,当有对数据进行修改操作的时候,复制共享锁的内容,单独进行修改,只有当事务提交了,才将排它锁释放,将数据写入共享内容中去。因为是每次查询完就释放锁,所以这样造成了不可重复读的问题)

2.不可重复读(Nonrepeatable Read)——在同一事务中,两次读取同一数据,得到内容不同。

事务T1:查询一条记录
         -->事务T2:更新(插入,删除)事务T1查询的记录
         -->事务T2:调用commit进行提交
事务T1:再次查询上次的记录
            
此时事务T1对同一数据查询了两次,可得到的内容不同,称为不可重复读。

注意:不可重复读重点在修改。

在基于锁的并行控制方法中,如果在执行select时不添加读锁,就会发生不可重复读问题。

在多版本并行控制机制中,当一个遇到提交冲突的事务需要回退但却被释放时,会发生不可重复读问题。

有两个策略可以防止这个问题的发生:

(1) 推迟事务2的执行,直至事务1提交或者回退。这种策略在使用锁时应用。

(2) 而在多版本并行控制中,事务2可以被先提交,而事务1继续执行在旧版本的数据上。当事务1终于尝试提交时,数据库会检验它的结果是否和事务1、事务2顺序执行时一样。如果是,则事务1提交成功;如果不是,事务1会被回退。

解决不可重复读问题:读取数据时加共享锁,写数据时加排他锁,都是事务提交才释放锁。读取时候不允许其他事物修改该数据,不管数据在事务过程中读取多少次,数据都是一致的,避免了不可重复读问题。(以前是每次读取完就释放锁,而现在,我们读取了不马上释放,也就是不让数据被写入)

3.幻读(Phantom——同一事务中,用同样的操作读取两次,得到的记录数不相同。 

详细解释:幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么,以后就会发生操作第一个事务的用户发现表中还没有修改的数据行,就好象发生了幻觉一样。

事务T1:查询表中所有记录
          -->事务T2:插入一条记录(满足事务T1更新数据的条件)
          -->事务T2:调用commit进行提交

事务T1:更新表中数据并且commit进行提交

同一个事务,第一次查询数据发现又50条满足条件,事务T2插入一些数据,这些数据有5条数据满足T1的条件,T2提交后T1才去按照第一次查询的去更新数据,同时commit,最后发现更新了55条数据,这就是“幻读”。

发生的情况:没有范围锁。读锁(共享锁),写锁(排他锁)他们两个是单独的。

如何避免:实行序列化隔离模式,在任何一个低级别的隔离中都可能会发生。

解决幻读问题:采用的是范围锁RangeS RangeS_S模式,锁定检索范围为只读,这样就避免了幻读问题。
4.丢失更新(Lost Update) 

事务T1读取了数据,并执行了一些操作,然后更新数据。事务T2也做相同的事,则T1和T2更新数据时可能会覆盖对方的更新,从而引起错误。

二、自己实验结果:

困难的是事务隔离级别的理解,我这儿对这进行分析一下:(注意,这些问题出现都是建立在基本写锁上面的,也就是操作完数据,不提交下一个就走不动)

Read uncommitted    存在的问题:脏读、不可重复读、幻读、丢失更新

Read committed     存在的问题:不可重复读、幻读、丢失更新

Repeatable read    存在的问题:幻读

Serializable    存在的问题:性能低每次做修改数据的操作,需要等待在前面开启事务的事务提交才能做(查询操作也需要排队)。

 

Read uncommitted   针对更新数据操作都有脏读问题;

Read committed   避免了所有更新数据操作的脏读问题,包括删除;

Repeatable read    避免了所有不可重复读的问题,其中包括由于更新,删除,和添加。

Serializable    解决了 幻读

猜你喜欢

转载自blog.csdn.net/zq1994520/article/details/82667231