我有一个使用 Mongoid 的 find_or_create_by 方法的网络应用程序。
poll = Poll.find_or_create_by(fields)
在我们投入生产之前,我正在尝试运行失败场景,我突然想到多个用户可以尝试使用此方法访问此资源。它是否有可能创建同一对象的多个实例?我能做些什么来防止这种情况发生?
我有一个使用 Mongoid 的 find_or_create_by 方法的网络应用程序。
poll = Poll.find_or_create_by(fields)
在我们投入生产之前,我正在尝试运行失败场景,我突然想到多个用户可以尝试使用此方法访问此资源。它是否有可能创建同一对象的多个实例?我能做些什么来防止这种情况发生?
免责声明:我是 Mongoid 和 Rails 的新手,所以我可能完全错了。
查看modifiable.rb和many.rb它似乎没有锁定任何资源。
在我看来,它只是执行“where().first”查询,然后如果没有返回任何内容,则执行“create”查询:
def find_or(method, attrs = {}, &block)
where(attrs).first || send(method, attrs, &block)
end
对于 find_or_create_by,“send”会调用“create_document”:
def create_document(method, attrs = nil, &block)
klass.__send__(method,
selector.reduce(attrs || {}) do |hash, (key, value)|
unless key.to_s =~ /\$/ || value.is_a?(Hash)
hash[key] = value
end
hash
end, &block)
end
结论:对我来说,这似乎是一种方便的方法,不要指望它是“线程安全的”。我希望有更多关于这种方法的文档。
有时在 MRI 中实现线程安全代码是不值得的。因为大多数时候我们必须进行多进程部署。所以最简单的解决方案是数据库级别的唯一性验证。
class Person
include Mongoid::Document
field :ssn
index({ ssn: 1 }, { unique: true })
end
所以当保存失败时回滚事务。请记住,模型级别的唯一性验证也容易出错。