数据库并发问题

以下内容为在数据库并发中出现的各种问题。

脏读(dirty read) 

A事务读到B事务刚修改的值,但是B事务撤销了,也A事务读到的值就是假的了。

时间
转账事务A
取款事务B
T1
 
开始事务
T2
开始事务
 
T3
     
查询账户余额为1000元    
T4
        
取出500元把余额改为500元
T5
查询账户余额为500元(脏读)
 
T6
 
撤销事务余额恢复为1000元
T7
汇入100元把余额改为600元
 
T8
提交事务
 
## 不可重复读(unrepeatable read) 

   不可重复读是指A事务读取了B事务已经提交的更改数据。假设A在取款事务的过程中,B往该账户转账100元,A两次读取账户的余额发生不一致:

时间
取款事务A
转账事务B
T1
 
开始事务
T2
开始事务
                          
T3
                              
查询账户余额为1000元     
T4
查询账户余额为1000元
                          
T5
                  
取出100元把余额改为900元
T6
 
提交事务                  
T7
查询账户余额为900元(和T4读取的不一致)
 
## 幻象读(phantom read) 

幻象读与不可重复读的区分是,前者是新增时出现,后者是更改或删除出现。     A事务读取B事务提交的新增数据,这时A事务将出现幻象读的问题。幻象读一般发生在计算统计数据的事务中,举一个例子,假设银行系统在同一个事务中,两次统计存款账户的总金额,在两次统计过程中,刚好新增了一个存款账户,并存入100元,这时,两次统计的总金额将不一致:  

时间
统计金额事务A
转账事务B
T1
 
开始事务
T2
开始事务
             
T3
统计总存款数为10000元
             
T4
 
新增一个存款账户,存款为100元
T5
 
提交事务     
T6
再次统计总存款数为10100元(幻象读)
 
    如果新增数据刚好满足事务的查询条件,这个新数据就进入了事务的视野,因而产生了两个统计不一致的情况。  **幻象读和不可重复读是两个容易混淆的概念**,前者是指读到了其它已经提交事务的新增数据,而后者是指读到了已经提交事务的更改数据(更改或删除),为了避免这两种情况,采取的对策是不同的,防止读取到更改数据,只需要对操作的数据添加行级锁,阻止操作中的数据发生变化,而防止读取到新增数据,则往往需要添加表级锁——将整个表锁定,防止新增数据(Oracle使用多版本数据的方式实现)。  ## 第一类丢失更新 

    A事务撤销时,把已经提交的B事务的更新数据覆盖了。这种错误可能造成很严重的问题,通过下面的账户取款转账就可以看出来: 

时间
取款事务A
转账事务B
T1
开始事务
 
T2
 
开始事务
T3
查询账户余额为1000元    
 
T4
 
查询账户余额为1000元
T5
 
汇入100元把余额改为1100元
T6
 
提交事务
T7
取出100元把余额改为900元
 
T8
撤销事务
 
T9
余额恢复为1000元(丢失更新)
 
A事务在撤销时,“不小心”将B事务已经转入账户的金额给抹去了。  ##  第二类丢失更新 

A事务覆盖B事务已经提交的数据,造成B事务所做操作丢失:  

时间
转账事务A
取款事务B
T1
 
开始事务
T2
开始事务
                         
T3
               
查询账户余额为1000元    
T4
查询账户余额为1000元
                         
T5
 
取出100元把余额改为900元
T6
 
提交事务           
T7
汇入100元
 
T8
提交事务
 
T9
把余额改为1100元(丢失更新)
 
    上面的例子里由于支票转账事务覆盖了取款事务对存款余额所做的更新,导致银行最后损失了100元,相反如果转账事务先提交,那么用户账户将损失100元。 **第一类丢失更新和第二类丢失更新的差别**:前者是由于撤销事务导致丢失更新,后者是因为更新被覆盖。 内容参考来源:
updatedupdated2024-08-302024-08-30