1.通过FOR UPDATE进行排他
①记录在修改之前先给它上锁,即:使用SELECT语句将要修改的记录取出来,并且在sql末加上“FOR UPDATE WAIT timeout时间”(SELECT ・・・ FOR UPDATE WAIT timeout时间)
见用户A的操作过程:
当其他用户想要修改这条记录时,发现这条记录被人上了锁,程序就会报错。
见用户B操作过程:
2.通过“修改时间”进行的排他处理
①在点击详细取得被修改数据详细内容时,取得该记录在数据库中的“修改时间”(或更新次数),我们称它为“修改时间1”。
②在点击确认进行正式修改时,再次从数据库中取得要修改记录的“修改时间”(或更新次数),我们称它为“修改时间2”。
然后比较“修改时间1”和“修改时间2”:
如果2者相等,则进行正常的修改操作,并将系统的当前时间写入该记录的“修改时间”字段。
如果发现2者不相等,说明该记录已经被他人修改了,程序就报错。
3.其实上述两种方法都有弊端,第一种方法的弊端是,如果一个用户锁定数据的时间比较长,那么其它用户将要等待很长时间;第二种方法的弊端是,如果两个用户“同时”更新数据的,那么数据库将无法判断到底要更新哪一个用户的请求。
比较好的做法是把两种方法结合起来。
①在点击详细取得被修改数据详细内容时,取得该记录在数据库中的“修改时间”,我们称它为“修改时间1”。
②在点击确认进行正式修改时,再次从数据库中取得要修改记录的“修改时间”,我们称它为“修改时间2”。
然后比较“修改时间1”和“修改时间2”:
如果2者相等,则进行正常的修改操作,并将系统的当前时间写入该记录的“修改时间”字段。
记录在修改之前先给它上锁,即:使用SELECT语句将要修改的记录取出来,并且在sql末加上“FOR UPDATE WAIT timeout时间” (SELECT ・・・ FOR UPDATE WAIT timeout时间)
对该条记录进行修改。修改完成,开锁。
如果发现2者不相等,说明该记录已经被他人修改了,程序就报错。
例子:以更新次数为例
详细画面初期化时取得更新次数
select upcount from table where key=?
如结果6,放于页面隐藏控件中
点提交按钮在数据库操作前,进行比较,并且锁定数据
select upcount from table where key=? and upcount =6 for update wait 5
如果2者相等修改数据
update table set item=?, upcount=upcount+1 where key=? and upcount=6
commit;
4、在oracle10g 中可以用ORA_ROWSCN 函数代替“更新次数”,ORA_ROWSCN是根据系统最后更新时间来进行计算。这个ORA_ROWSCN。在默认情况下是采用数据块为单位的,也就是一个数据库块(block)上共享一个ORA_ROWSCN,当数据更新的时候,这个block快的ORA_ROWSCN就会自动更新。所以在默认情况下的话,有可能出现假冲突的情况。比如A,B,C,D四条数据都在一个block上,这个时候A数据更新了,ORA_ROWSCN也会更新,这个时候因为ABCD四条数据存储在一个block上,所以BCD的ORA_ROWSCN也更新过了,其实BCD三条数据并没有更新过,这个就造成了假更新的情况出现。
利用Oracle 9i提供的ROWDEPENDENCIES建表关键字可以解决上面的问题。这个关键字在Oracle9i中是为了增加行依赖性跟踪特性的,支持推进复制。在Oracle10g中有可以用来做行级别的ORA_ROWSCN用了。用这个关键字建表以后,在每行会增加一个隐藏的COLUMN,所以每行会增加6个byte的开销。
这样做的好处是不用再增加一个额外的域,而是由Oracle的ORA_ROWSCN来维护数据,数据开销不是很大,并且减少了出错的可能。缺点就是要重新建表。
create table test(id number(10), ....) ROWDEPENDENCIES
修改前的 ORA_ROWSCN 的值
select id ,ORA_ROWSCN from test
修改数据
update test set name = name || to_char(id) where id = 1 ;
修改后的 ORA_ROWSCN 的值
select id ,ORA_ROWSCN from test
只有第一行的数据的 ORA_ROWSCN 改变了,其它行未改变。