问题
I have a web app that uses Mongoid's find_or_create_by method.
poll = Poll.find_or_create_by(fields)
Before we go into production, I am trying to run through the failure scenarios, and it occurred to me that multiple users could try to access this resource using this method. Is there any likelihood that it could create multiple instances of the same object? What can I do to prevent that?
回答1:
Disclaimer: I'm new to Mongoid and Rails so I could be totally wrong.
Looking at modifiable.rb and many.rb it doesn't appear to lock on any resource.
It looks to me like it simply does a "where().first" query and then if that does not return anything it performs a "create" query:
def find_or(method, attrs = {}, &block)
where(attrs).first || send(method, attrs, &block)
end
For find_or_create_by, "send" would call "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
Conclusion: To me this appears to be a convenience method, do not expect it to be "thread-safe". I wish there was more documentation available on this method.
回答2:
sometimes it is not worth to implement a thread-safe code in MRI. because most of the time we have to go multiprocess deployments. so the easiest solution is database level uniqueness validations.
class Person
include Mongoid::Document
field :ssn
index({ ssn: 1 }, { unique: true })
end
so when save failed rollback the transaction. keep in mind that model level uniqueness validation is also error-prone.
来源:https://stackoverflow.com/questions/13072866/is-find-or-create-by-thread-safe-in-mongoid