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