脏读,不可重复读,幻读,丢失更新

数据库事务(简称:事务)是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。

当多个用户并发操作数据库时,数据库为每一个用户开启不同的事务。这些事务如果不加以隔离,会产生一些问题。看下面的例子:

脏读  事务A  事务B
前提 Amy账户余额是100  
时间1: B事务开始    Bob给自己老妈转500,结果转给了Amy,这个事务做了,但未提交
时间2: A事务开始,并完成 如果Amy可以读取未提交的数据,这时候她会查到余额为600  
时间3: B事务回滚   Bob意识到自己的错误,回滚刚才的事务
总结 100才是Amy真实的余额,600为脏数据读取的产物,是实实在在的误导。 

 

不可重复读  事务A  事务B
前提 Amy账户余额是100  
时间1: A事务开始  Amy查询到自己的余额是100  
时间2: B事务开始,并完成    Bob给Amy转了500
时间3: A事务重复,并完成 Amy查询到自己的余额是600  
总结

在事务A存续期间,针对相同的数据做了两次相同的查询,但数额不同(尽管数额都是当时时间点真实的余额)。

知道真相的也就算了,不知道的以为自己被欺负/骗/耍了。 

 

幻读  事务A  事务B
前提 Amy在某app买了三份基金,当前金额分别是300,600,900  
时间1: A事务开始  Amy查询,当前持有金额 >500 的基金个数为多少?结果返回2个  
时间2: B事务开始,并完成    三个产品分别被扣了管理费100块,成了100,500,800
时间3: A事务重复,并完成 Amy查询,当前持有金额 >500 的基金个数为多少?结果返回1个  
总结

在事务A存续期间,针对同一批数据做了两次相同的检索,但得结果不同(尽管检索出来的数据在当时时间点是真实的)。

知道真相的也就算了,不知道的以为自己被欺负/骗/耍了。

 

归纳一下这些问题的特点:

问题 特点1 特点2 特点3**
脏读  Dirty read

某事务A读取了另一事务B未提交的数据

注:未提交意味着之后会有提交和回滚两个状态,回滚才是导造成A读数据前后不一致的根本原因;但一般认为,只要是A读了B未提交的数据,就是脏读

   
不可重复读 Non-repeatable read 某事务A读取了另一事务B已提交的数据 A查询的是某一个数据项 重点在于更新修改数据
幻读 Phantom read 某事务A读取了另一事务B已提交的数据 A查询的是一批数据整体(如个数) 重点在于新增或删除数据 

对于特点3**来说,还有一种解释:

不可重复读重点在于update和delete,而幻读的重点在于insert。如果用锁机制来解释的话,即想要避免“不可重复读”,在事务A第一次读数据的时候,把这些数据加锁,就可以阻止update和delete操作,其他事物无法改写数据。但这个方法不能阻止另一个事务B进行insert操作,之后A会发现莫名其妙多了一条数据,即发生了幻读。幻读需要靠Serializable隔离级别来避免(即读用读锁,写用写锁,读锁和写锁互斥,但会极大的降低数据库的并发能力),所以说,不可重复读和幻读,从锁机制角度来说,区别比较大,也可以认为,从控制的角度来看, 两者的区别就比较大。

不可重复读, 只需要锁住满足条件的记录 
幻读, 要锁住满足条件及其相近的记录 

 

其实,除了脏读不可重复读幻读,还有另一种问题,丢失更新,即两个事务同时读取同一条记录,A先修改记录,B也修改记录(B是不知道A修改过),B提交数据后B的修改结果覆盖了A的修改结果。

 

posted @ 2019-08-02 13:50  柳思颐开心的一天  阅读(297)  评论(0编辑  收藏  举报