Race conditions in Rails first_or_create

扶醉桌前 提交于 2020-01-01 02:16:09

问题


I'm trying to enforce uniqueness of values in one of my table fields. Changing the table isn't an option. I need to use ActiveRecord to conditionally insert a row into the table but I'm concerned about synchronization.

Does first_or_create in Rails ActiveRecord prevent race conditions?

This is the source code for first_or_create from GitHub:

def first_or_create(attributes = nil, options = {}, &block)
  first || create(attributes, options, &block)
end

Is it possible that a duplicate entry will result in the database due to synchronization issues with multiple processes?


回答1:


Yes, it's possible.

You can significantly reduce the chance of conflict with either optimistic or pessimistic locking. Of course optimistic locking requires adding a field to the table, and pessimistic locking doesn't scale as well--plus, it depends on your data store's capabilities.

I'm not sure whether you need the extra protection, but it's available.




回答2:


The Rails 4 documentation for find_or_create_by provides a tip that may be useful for this situation:

Please note this method is not atomic, it runs first a SELECT, and if there are no results an INSERT is attempted. If there are other threads or processes there is a race condition between both calls and it could be the case that you end up with two similar records.

Whether that is a problem or not depends on the logic of the application, but in the particular case in which rows have a UNIQUE constraint an exception may be raised, just retry:

begin
  CreditAccount.find_or_create_by(user_id: user.id)
rescue ActiveRecord::RecordNotUnique
  retry
end

Similar error catching may be useful for Rails 3. (Not sure if the same ActiveRecord::RecordNotUnique error is thrown in Rails 3, so your implementation may need to be different.)



来源:https://stackoverflow.com/questions/10641647/race-conditions-in-rails-first-or-create

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!