在Mongoid中find_or_create_by是否安全?

时间:2012-10-25 16:15:38

标签: ruby-on-rails thread-safety mongoid

我有一个使用Mongoid的find_or_create_by方法的网络应用程序。

poll = Poll.find_or_create_by(fields)

在我们投入生产之前,我正在尝试运行故障情况,并且我发现多个用户可能尝试使用此方法访问此资源。是否有可能创建同一对象的多个实例?我该怎么做才能防止这种情况?

2 个答案:

答案 0 :(得分:2)

免责声明:我是Mongoid和Rails的新手,所以我可能完全错了。

查看modifiable.rbmany.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。请记住,模型级别的唯一性验证也容易出错。