一、不管是選擇悲觀鎖策略,仍是樂觀鎖策略。若是一個對象被上了鎖,那麼該對象都會受這個鎖的控制和影響。若是這個鎖是個排它鎖,那麼其它會話都不能修改它。
二、選擇悲觀鎖策略,仍是樂觀鎖策略,這主要是由應用和業務需求來肯定的。若是你的應用和業務常常會出現從我看到要修改的記錄的值,到我修改完成該記錄這個時間段內,該記錄有較大機率被其它會話所修改。換句話說就是,在我真正去作出修改時,這個記錄的值極可能已經與我當初看到的不一樣了。那麼這時,採起悲觀鎖策略,也許是更好的。而採起悲觀鎖策略的一個典型操做就是 select ... for undate。經過這種操做,使得從我一開始查看該記錄起,這條記錄就被上了排它鎖,不容許其它會話再對該記錄有任何修改。
相對的,若是你的業務和應用基本上不多出現這種情景,那麼選擇樂觀鎖策略也許就會更好。
三、這兩種策略的核心其實就是持有鎖的時間的起止點不一樣,悲觀鎖是從讀取記錄的那一刻就開始了,而樂觀鎖只從UPDATE那一刻開始;結束的點二者是同樣的,都是發出commit或rollback命令。因此,悲觀鎖策略會使鎖的持續時間更長,而樂觀鎖的持續時間則較短。其影響就是併發。悲觀鎖的併發性低於樂觀鎖。
四、不管是採用哪一種策略,都要保證數據的完整性。因此,在採用樂觀鎖策略時,是有可能出現數據的不完整。舉例來講:儲戶甲的存款餘額100元,假設在幾乎相同的時刻,發生了兩筆業務,業務1爲其存入了50元,另外一個業務是其網上購物消費了30元。顯然,這兩個操做結束後,甲的存款餘額應爲120元(100+50-30)。但咱們設想一下在數據庫層面,可能出現這種狀況,當其在銀行櫃檯存入50元時,銀行操做員收到了甲存入的50元現金,並經過 select 語句看到甲的當前餘額爲100元(其發出的指令是下面的語句:
select 餘額
from 存款餘額表
where 儲戶賬號=儲戶甲的銀行賬號;)
,接着,發出指令
update 存款餘額表
set 餘額=150
where 儲戶賬號=儲戶甲的銀行賬號;
但就在其看到甲的餘額爲100元,到其修改甲的餘額爲150這期間,甲在網上的消費行爲致使交易系統已經將甲的餘額變成了70元(100-30)並提交了。當銀行員工發出的指令也被提交後,甲的餘額變成了150元,至關於甲網上消費的行爲沒有產生任何扣款。這顯然是不正確的,更是要避免出現的。
若是這套系統採用的是悲觀鎖策略,那麼在從銀行員工查看甲當前餘額的那一個時刻起(這時查詢的指令就會是:
select 餘額
from 存款餘額表
where 儲戶賬號=儲戶甲的銀行賬號 for update;)
該記錄就已經被鎖定了,這時甲網上消費的行爲致使的交易系統從甲的賬戶中扣減的操做就會處於等待狀態。直至銀行員工提交了相關指令,交易系統才能去扣減甲的錢款。這樣,就能夠確保甲的賬戶餘額是正確的。
悲觀鎖的策略顯然能夠保證業務的正確性和完整性。但再設想一下,若是甲在存款時,銀行員工內急,或者儲戶甲說等一等,我要考慮一下是否再多存一些。那麼,銀行員工的操做就不會提交,這時網上交易系統對甲賬戶的扣款操做就會一直處於等待狀態,或者在等待必定時間後,返回一個扣款失敗的提示。這對於系統的效率和客戶來講,都不是一個好的體驗。
五、由於考慮到樂觀鎖策略能夠產生的這種問題,因此,咱們在設計應用時,能夠採起一些其它方法來避免上述狀況的發生。其思想就是在真正提交時,確認要修改的數據沒有變化過。主要的方法以下:
(1)、更新時帶入原始的數據。
update 存款餘額表
set 餘額=150
where 儲戶賬號=儲戶甲的銀行賬號 and 餘額=100;
(2)、在記錄上增長修改的時間戳(也可利用ora_rowscn僞列)。即在事務開始時,獲取該記錄的時間戳,修改時,校驗該時間戳,若一致則修改。
六、其實,我上面舉的這個例子,若是在業務設計時,選擇更新指令爲
update 存款餘額表
set 餘額=餘額+50
where 儲戶賬號=儲戶甲的銀行賬號;
那麼,即便是在樂觀鎖策略的狀況下,依然能夠保證數據的正確性和完整性。php
---引自 http://www.itpub.net/forum.php?mod=viewthread&tid=1928001數據庫