2015-12-28 41 views
2

我嘗試了很多新想法(DDD,Event Sourcing和CQRS)並評估RethinkDB作爲域事件的潛在數據存儲。在DDD中,聚合是一組對象,它們一起工作以提供特定的行爲。每個聚合都是一個事務/一致性邊界。聚合的根是提供API並隱藏內部實現的對象。RethinkDB - 這是一個有效的樂觀鎖定實現

要持久化聚合,通常建議使用樂觀鎖定。我們的想法是在聚合中有一個版本號屬性,當保存一個聚合時,我們會檢查數據庫中聚集的版本是否與應用程序中讀取/更新聚合的版本相匹配。這保證沒有人在此期間改變彙總並防止覆蓋其他更改。

顯然,這個版本檢查不能發生在應用程序層(想想多個應用程序服務器場景)。應用程序需要來自數據存儲的支持來進行考慮此版本號的原子更新。

這是一個使用RethinkDB Ruby API的簡單實現。

我創建了一個名爲「申請」表,一個記錄

"id": "6b3b57a7-3ba8-4322-873e-1d6c8333daae" , 
"name": "Homer Simpson" , 
"updated_at": Mon Dec 28 2015 12:05:40 GMT+05:30 , 
"version": 1 

這裏是我在平行

require 'rethinkdb' 
include RethinkDB::Shortcuts 

conn = r.connect(:host => 'localhost', 
      :port => 28015, 
      :db => 'test') 

def update_applicant(conn, current_version) 
    result = r.table('applicants').get('6b3b57a7-3ba8-4322-873e-1d6c8333daae').update{ |applicant| 
    r.branch(
     applicant['version'].eq(current_version), 
     {updated_at: Time.now, version: current_version + 1}, 
     {} 
) 
}.run(conn) 

    fail 'optimistic locking failure' if result['unchanged'] == 1 
rescue => e 
puts "optimistic locking failure: #{current_version}" 
current_version = r.table('applicants').get('6b3b57a7-3ba8-4322-873e-1d6c8333daae').run(conn)['version'] 
retry 
end 

(1..100).each { |version| update_applicant(conn, version) } 

conn.close 

這似乎是工作跑了兩次的樣本測試代碼,但我想打確保在生產環境中不會出現這種方法的競爭條件和其他問題。我假設更新是一個原子操作,並在更新中使用分支仍然保持原子。

我正在尋找來自RethinkDB devs/users的一些驗證和建議。謝謝。

回答

4

update總是一個原子操作,除非您傳遞non_atomic: true標誌(如果更新包含非確定操作,有時這是必需的),以便代碼對我來說看起來很安全。

+0

感謝您的回覆。 –