分类:
2008-10-27 14:27:46
SQL> create t(id number,nick varchar2(32),status number,email varchar2(32),gmt_modified date);
Table created. SQL> desc t; SQL> begin QL procedure successfully completed. SQL> alter nls_date_='YYYY-MM-DD HH24:MI:SS'; Session altered. SQL> select * from t; ID NK STATUS EMAIL GMT_MODIFIED 1 updated. SQL> select * from t; ID NICK STATUS EMAIL GMT_MODIFIED --session 2也执行这样的语句,出现等待。 --session 1提交 --session 2执行完成,查看结果 ID NICK STATUS EMAIL GMT_MODIFIED |
上面运行的更新语句
update t set status=1,gmt_modified=sysdate where id in ( select id from (select id from t where nick='test' and status=0 order by id asc) where rownum < 2) and status=0; --注意此条件 |
当session 1执行,但并不提交后,session 2执行相同的语句,由于update语句中有select子查询,众所周知,select要进行一致性读,即也会读取到记录1,但这又是一个update语句,会进行当前读,session 2也想去更新这一行,但发现这一行已被另外一个事务更新,所以出现等待。但当session 1提交后,通过以上实验,证明session 2会再次触发一致性读与当前读,去更新了满足条件的第二行,而不是第一行。
大家还可以做其它实验,比如说session 1执行如下的语句:
update t set status=1,gmt_modified=sysdate where id in ( select id from (select id from t where nick='test' and status=0 order by id asc) where rownum < 2) and status=0; --注意此条件 |
session 2执行如下的语句:
update t set status=1,gmt_modified=sysdate where id in ( select id from (select id from t where nick='test' and status=0 order by id asc) where rownum < 4) and status=0; --注意此条件 |
结果是sesion 1更新了1条;session 2更新了2条,而session 2实际想更新3条。
本篇实验也提供了一个很好处理并发的方法,使用此方法,可以保证多个更新在并发时不会更新同一行,不过要在更新后,加一个判断,如果实际更新的条数 != 想要更新的条数(即sql语句中的rownum),那就说明出现了并发,并且剩余的满足条件的记录数不满足应用要求,这时候就需要在应用层加上进一步的并发处理了。我们在实际中出现的一个案例,恰好就是没有对实际更新的条目进行判断,导致出现了应用层数据逻辑错误。