首页 > Linux操作系统 > Linux操作系统 > 并发容易出现的问题与并发控制
作者:PINNER(转载)
在多进程连接的数据库,并发操作是一个很平常的现象,加上Oracle特有的锁机制(不阻塞读),所以理解与控制并发是一个非常重要的事情。
下面用一个简单的例子说明并发处理中的一个问题,如用户表中存放好评的统计数据,假定两个用户同时操作,看如下一个过程。
one session other session
-----------------------------------------------------------------------------------------
T1> SQL>insert into auction_feedbacks values(?)
1 row inserted
T2> SQL>insert into auction_feedbacks values(?)
1 row inserted
T3> SQL> update bmw_users set rated_sum =
(select count(*) from auction_feedbacks
where username=?)
where id=?;
1 row updated
T4> SQL> update bmw_users set rated_sum =
(select count(*) from auction_feedbacks
where username=?)
where id=?;
1 row updated
T5>SQL> commit;
Commit complete
T6> SQL> commit;
Commit complete
其中时间T1 两个会话,同样的执行语句与同样的执行顺序,都想把增加到好评表中的好评统计放到用户表中去,但是,问题出来了,假定原来该用户的好评是20个,经过两个人的评价后,好评表中最后是22条记录了,而用户表的统计数据是21。 错在哪里?谁都没有错,是并发引发的问题。 要控制好并发,就要深刻理解Oracle的锁机制,Oracle如果一个进程发生数据改变,另外一个进程读该数据的时候,将发生一致性读(以SCN为基准),所以在上面的例子中,进程2读到了进程1 commit之前的统计数,这样就漏掉了会话1发生的好评。 我们要怎么避免并发呢,其实Oracle除了支持一致性读,也支持当前读,也就是说,操作之前检查最新的状态,对于select 可以用序列事务,对于DML本来就是当前读,所以,我们可以利用update的条件中增加需要更新值的原始值来避免并发。 我们利用用户表复制中的防止并发操作来说明,同样的两个会话 会话一 会话二 执行同样的语句,如果会话1先执行但是还没有提交的时候,会话2处于等待状态,但是会话1一旦提交,会话2的条件“where f.run_flag=’stop’”的检查将失效(当前读已经是runing,是会话1提交后的数据),所以会话2能更新到的记录数将是0。通过判断sql%rowcount返回的处理行数就可以决定是否继续,如上面的例子,如更新到的行数返回0,将退出或者是等待。 如果在业务频繁的表上面,也可以与实际业务结合起来,如要把表的字段a增加10,可以这样操作 在以上例子中,假定原表a的值是10,该语句就可以保证只能有一个进程能更新成功。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/127656/viewspace-331193/ ,如需转载,请注明出处,否则将追究法律责任。