在學習Rails中的並發處理的處理前,我們先簡單了解下並發處理的概念。
在有多個處理同時訪問同一個數據庫的應用程序中,可能會出現這樣的情況,因為一個處理更新了數據庫中的行,而使得另一個處理中持有的數據變得陳舊了。例如,A和B先後從數據庫中提取了相同的數據,並都做了修改,這時B先將自己的修改更新會數據庫,稍後,A將自己的修改更新回數據庫,這時將會覆蓋B所作的修改,當B再次提取數據庫後,看到的是A修改的結果,而不是自己的。
一個解決辦法就是將更新的表或者行進行鎖定,防止其他程序進行更新或者訪問,鎖定可以完全避免並發的問題,也常稱作悲觀鎖,但是在Web項目中,這個做法是行不通的,因為在同一個時間點上,可能會有很多個用戶需要訪問數據。
樂觀鎖並沒有將數據鎖定的外在表現,作為替代,在將修改寫回到數據庫之前,進行檢查來確定一條記錄是否已經被修改了。在Rails裡的實現方法是,每和行都包含有一個版本號(version number),不管什麼時候行被更新了,版本號就會被增加,當你在你的程序中進行一個更新操作時,Active Record檢查行和Model的版本號,如果不匹配,將會放棄修改並拋出一個異常。
對於任何一個包含有integer型的字段lock_version的表,樂觀鎖都會默認的被啟用,你可以把新行的這個字段初始為0,但是,如果你忘記了,Active Record也會替你完成。
我們來看看怎樣實現樂觀鎖,我們創建一個名為counters的表:
create table counters ( id int not null auto_increment, count int default 0, lock_version int default 0, primary key (id) );
然後我給這個表創建一個行,將這個行讀入到不同的Model中,並且在其中嘗試更新,
class Counter < ActiveRecord::Base end Counter.delete_all Counter.create(:count => 0) count1 = Counter.find(:first) count2 = Counter.find(:first) count1.count += 3 count1.save count2.count += 4 count2.save
當我們運行上面的代碼,會得到一個異常,Rails會放棄count2所作的修改,因為其中包含的已經是髒數據了。
如果使用了樂觀鎖,就需要在程序中處理這些異常,也可以禁用樂觀鎖:
ActiveRecord::Base.lock_optimistically = false
關於樂觀鎖,可以參考Martin Flower所著的《企業應用解決方案及模式》一種中關於並發處理和工作單元(Work Unit)模式的內容,相信對Rails的並發處理機制會有更深的了解。