RethinkDB - 这是一个有效的乐观锁定实现

时间:2015-12-28 07:15:21

标签: rethinkdb

我正在尝试很多新想法(DDD,Event Sourcing和CQRS)并将RethinkDB评估为域事件的潜在数据存储。在DDD中,聚合是一组协同工作以提供特定行为的对象。每个聚合都是事务/一致性边界。聚合的根是一个提供API并隐藏内部实现的对象。

要持久化聚合,通常建议使用乐观锁定。我们的想法是在聚合中拥有版本号属性,当需要保存聚合时,我们会检查以确保数据库中聚合的版本与应用程序中读取/更新的聚合版本相匹配。这保证了在此期间没有人改变聚合并防止覆盖其他改变。

显然,这种版本检查不仅仅发生在应用层(想想多个应用服务器场景)。应用程序需要来自数据存储的支持,以进行考虑此版本号的原子更新。

这是一个使用RethinkDB Ruby API的简单实现。

我创建了一个名为'applicants'的表,其中包含一条记录

"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开发者/用户的一些验证和建议。感谢。

1 个答案:

答案 0 :(得分:4)

update始终是一个原子操作,除非你传递non_atomic: true标志(如果更新包含非确定性操作,有时需要这样做),这样代码对我来说是安全的。

相关问题