文章出处:孙卫琴老师-精通Hibernate
在并发的环境之中,一个数据库系统会同时为各种各样的客户端提供服务,对于同时运行的多个事务,当这些事务访问数据库中相同的数据时如果没有采取必要的隔离机制,就会出现各种并发问题,可以把这些问题归纳为一下五种:
假设现在一所银行有一个取款事务和一个支票转账事务操作同一个银行账户的情形,首先我们假设两个事务顺序执行,而不是并发执行,那麽整个的步骤如下:
---- 银行客户在银行前台请求取款100元,出纳员先查询账户信息,得知存款余额为1000元。
---- 出纳员判断存款余额大于取款额,支付给客户100元,并将账户上的存款余额改为900元。
---- 出纳员处理一张转账支票,该支票向此账户汇入100元,出纳员先查询账户信息,得知存款余额为900元。
---- 出纳员将存款余额改为1000元。
可以很清楚的看到,如果顺序的执行这两个事务,不会出现任何问题,可是现实之中并非如此简单,如果两个事务分别由两个出纳员同时执行那麽可能就会出现并发的问题,下面我们分别来介绍:
1.第一类丢失更新
时 间 取款事务 转账事务
--------------------------------------------------------------------------------------------
T1 开始事务
T2 开始事务
T3 查询账户余额为1000元
T4 查询账户余额为1000元
T5 汇入100元把余额改为1100元
T6 提交事务
T7 取出100元把余额改为900元
T8 撤销事务余额恢复为1000元
----------------------------------------------------------------------------------------------
如果按照以上的时间次序并发执行的话,由于支票转账事务对存款余额所做的更新被取款事务的撤销所覆盖,所以客户会损失100元。
2.脏 读
时 间 取款事务 转账事务
----------------------------------------------------------------------------------------------
T1 开始事务
T2 开始事务
T3 查询账户余额为1000元
T4
T5 取出100元把余额改为900元
T6 查询账户余额为900元(脏读)
T7 撤销事务余额恢复为1000元
T8 汇入100元把余额改为1000元
T9 提交事务
----------------------------------------------------------------------------------------------
由于支票转账事务查询了取款事务未提交的更新数据,并且在这个查询结果的基础上进行了更新操作,如果取款事务最后被撤销 ,会导致银行客户损失100元。
3.虚 读
下面我们另举一个例子来看看什么是虚读。
时 间 注册事务 统计事务
----------------------------------------------------------------------------------------------
T1 开始事务
T2 开始事务
T3 统计注册客户总数为10000人
T4 注册一个新用户
T5 提交事务
T6 统计注册客户总数为10001人
T7 到底哪一个统计数据有效?
-----------------------------------------------------------------------------------------------
统计事务无法相信查询的结果,因为查询结果是不确定的,随时可能被其他事务改变。
对于实际应用,在一个事务中不会对相同的数据查询两次,假定统计事务在T3时刻统计注册客户的总数,执行SELECT语句,在T6时刻不再查询数据库,而 是直接打印统计结果为10000,这个统计结果与数据库当中数据是有所出入的,确切的说,它反映的是T3时刻的数据状态,而不是当前的数据状态。应该根据 实际需要来决定是否允许虚读。以上面的统计事务为例,如果仅仅想大致了解一下注册客户总数,那麽可以允许虚读;如果在一个事务中,会依据查询结果来做出精 确的决策,那麽就必须采取必要的事务隔离措施,避免虚读。
4.不可重复读
时 间 取款事务 转账事务
----------------------------------------------------------------------------------------------
T1 开始事务
T2 开始事务
T3 查询账户余额为1000元
T4 查询账户余额为1000元
T5 取出100元把余额改为900元
T6 提交事务
T7 查询账户余额为900元
T8 余额到底是1000元还是900元?
----------------------------------------------------------------------------------------------- 如上面所示,如果支票转账事务两次查询账户的存款余额,但得到了不同的查询结果,这使得银行出纳员无法相信查询结果,因为查询结果是不确定的,随时可能被其他事务改变。
5.第二类丢失更新
时 间 取款事务 转账事务
----------------------------------------------------------------------------------------------
T1 开始事务
T2 开始事务
T3 查询账户余额为1000元
T4 查询账户余额为1000元
T5 取出100元把余额改为900元
T6 提交事务
T7
T8 汇入100元把余额改为1100元
T9 提交事务
----------------------------------------------------------------------------------------------
每个事务都不知道其他事务的存在,最后一个事务对记录所做的更新将覆盖由其他事务对记录所做的已提交的更新。上面的例子里由于支票转账事务覆盖了取款事务对存款余额所做的更新,导致银行最后损失了100元