数据库并发写入问题-丢失更新与写入偏差
作者:互联网
MVCC
https://blog.csdn.net/qq_41775852/article/details/104853909
数据库中的MVCC多版本并发控制(快照隔离)可以避免事务并发时的脏读、不可重复读以及幻读的问题,但是却无法避免丢失更新以及写入偏差的问题。
丢失更新和写入偏差
-
丢失更新:两个事务并发读取同一记录,并在此基础上修改记录,并将其写回数据库,第二次写入的结果会覆盖第一次写入的结果,导致数据库状态不一致。(丢失更新不仅出现在数据库中,在应用程序多线程并发修改变量、分布式系统多主复制和无主复制中都会遇见)
例如:以下两个事务,对A变量进行读取10,T1事务将其减5,T2事务将其减8,两事务提交之后,A的状态为2,即T1事务的更新丢失了。如果A代表账户余额,这种错误是不可接受的。
-
写入偏差:写入偏差可视为丢失更新问题的一般化,如果两个事务读取相同的记录集,然后更新记录集,不同的事务可能更新(插入、删除)不同的记录,则可能发生写入偏差,导致数据库状态不一致或者不符合约束条件。
比如:1.医院规定必须至少有一名医生在值班。而两个值班医生同时进行请假事务,由于快照隔离,两个医生在检查当前值班医生数量时结果都为2,所以他们都可能请假。但是两个事务提交之后,却没有医生值班了,违反了医院的规定。2.两个用户同时修改唯一用户名,由于快照隔离,两人都发现数据库中无重复用户名,则修改成功。两个修改事务提交后,却出现用户名冲突。
如果并发事务没有先读取记录集的值,而是直接写入新的记录集值,个人认为不属于丢失更新或者写入偏差,因为这导致的数据库不一致,是用户的错误逻辑所导致的,不是事务并发的原因。
丢失更新和写入偏差的原因是相同的:并发事务首先查询得到了相同的记录集,然后根据此记录集进行更新、插入、删除等动作。由于快照隔离,事务感受不到其他事务对记录集的更改,所以可以成功提交事务。但是并发事务的修改却出现了矛盾,导致数据库不一致。
解决方法
CAS
比较并设置(CAS, Compare And Set)是一种原子操作,此操作的目的是为了避免丢失更新:只有当前值从上次读取时一直未改变,才允许更新发生。如果当前值与先前读取的值不匹配,则更新不起作用,且必须重试读取-修改-写入序列。但是在提供快照隔离的事务中不起作用。
显示锁定
由于并发事务的更改都是基于读取到的记录集,所以只要事务对读取到的记录集加排他锁,然后再对记录集更新,提交事务之后才释放排他锁。这样并发事务就只能读取到其他事务以及提交后的数据,则不会出现不一致的状态。
比如对于医生请假事务,读取并锁定所有医生的值班状态,修改自己的值班状态为请假,提交事务后释放锁。则第二个医生在请假事务中读取所有医生值班状态会阻塞,直到上一个事务提交,发现只剩自己一个人值班,则无法请假。
序列化隔离级别
使用事务的序列化隔离级别可以避免丢失更新和写入偏差。
标签:事务,读取,记录集,写入,更新,并发,数据库 来源: https://blog.csdn.net/qq_41775852/article/details/111916026