多使用者同時存取同一筆資料時,若無協調機制,後寫入者會覆蓋先寫入者的修改(Lost Update)。Rails 採用樂觀鎖解決此問題。
資料表加入 lock_version 整數欄位(預設 0),每次更新自動遞增。ActiveRecord 更新時比對模型與資料庫版本號,不符則拋出 ActiveRecord::StaleObjectError。
create table counters ( id int not null auto_increment, count int default 0, lock_version int default 0, primary key (id) );
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 # 成功,lock_version 變 1 count2.count += 4 count2.save # 拋出 StaleObjectError,count2 修改被放棄
應用程式需 rescue 處理衝突(如重試、提示使用者重新編輯)。若不需樂觀鎖,可全域停用:
ActiveRecord::Base.lock_optimistically = false
Martin Fowler 《企業應用架構模式》中關於「樂觀離線鎖」與「工作單元」模式的章節,有助於深入理解並發控制原理。