Mongoid 3 中 Rails 模型的强一致性

Strong consistency for a Rails model in Mongoid 3

我希望特定模型的所有数据库交互都通过集群中的 mongo 主节点,因此我将模型设置为使用强一致性。

class Photo
  include Mongoid::Document
  with consistency: :strong

  field :number, type: Integer
  # let's say a photo number is unique in the db
  validate :unique_number
end

但这似乎不起作用,因为当我保存两张非常靠近的照片时,我仍然 运行 验证错误。

photo1 # db has number=1 for this object
photo1.update_attributes(number: 2)
photo2.number = 1
photo2.save! # <= this raises a validation exception

我对强一致性的理解是这里不应该有一个race。它应该先写,然后再读,因为它都在主服务器之外,所以不应该有冲突。我错过了什么?

你所经历的好像是坚持。 update_attributes 正在对文档进行原子更改,看起来它没有更新持久化 photo1.Your photo2 验证是从持久性内部触发的(即在 rails 服务器上,而不是在 mongo) 并正在查看它拥有的记录。如果您在 photo1.update_attributes 之后 运行 photo1.reload 这可能会为您排序。

好久没用了mongoid 3, 4是state一段时间了,最​​近升级到5.You不会在[=22=中发现这类问题]id 4.

如果重新加载没有帮助,请输出 photo2.errors 以便我为您指出问题所在。

事实证明,在 class 级别调用 with(consistency: :strong) 只会将其应用于 下一个查询 。所以在加载class时调用class方法,为第一个查询设置强一致性, 但是后续查询不会触发相同的 class 方法,从而使它们的持久性操作以最终一致性进行操作。来自 Mongoid 3.1.7 documentation:

Tell the next persistance [sic] operation to store in a specific collection, database or session.

此方法不强制执行可以传入的持久化选项(与 class 中的其他一些方法一样),因此我们也可以传入 consistency: :strong.

黑客修复

为了将其应用于每个*持久性操作,我将其添加到 default_scope

class App
  default_scope -> { with(consistency: :strong); where({}) }
end

在这种情况下,默认范围期望有一个 Mongoid Criteria 对象 returned,所以我们 return 在设置一致性级别后的 noop where 子句-进度持久化操作。

* 如果开发人员决定调用 unscoped 并删除 default_scope.

,则不会应用此选项