我有一个使用Mongoid的find_or_create_by方法的网络应用程序。
poll = Poll.find_or_create_by(fields)
在我们投入生产之前,我正在尝试运行故障情况,并且我发现多个用户可能尝试使用此方法访问此资源。是否有可能创建同一对象的多个实例?我该怎么做才能防止这种情况?
答案 0 :(得分:2)
免责声明:我是Mongoid和Rails的新手,所以我可能完全错了。
查看modifiable.rb和many.rb,它似乎无法锁定任何资源。
在我看来,它只是简单地执行“where()。first”查询,然后如果它不返回任何内容,则会执行“创建”查询:
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
结论:对我来说这似乎是一种方便的方法,不要指望它是“线程安全的”。我希望有更多关于此方法的文档。
答案 1 :(得分:0)
有时不值得在MRI中实现线程安全代码。因为大多数时候我们必须进行多进程部署。因此最简单的解决方案是数据库级别的唯一性验证。
class Person
include Mongoid::Document
field :ssn
index({ ssn: 1 }, { unique: true })
end
因此,如果保存失败,将回滚transaction。请记住,模型级别的唯一性验证也容易出错。