Rails:ActiveRecord:RecordNotUnique with first_or_create [英] Rails: ActiveRecord:RecordNotUnique with first_or_create

查看:537
本文介绍了Rails:ActiveRecord:RecordNotUnique with first_or_create的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的模型表中有这个索引:

I have this index in my Model's table:

UNIQUE KEY `index_panel_user_offer_visits_on_offer_id_and_panel_user_id` (`offer_id`,`panel_user_id`)

此代码:

def get_offer_visit(offer_id, panel_user_id)
  PanelUserOfferVisit.where(:offer_id => offer_id, :panel_user_id => panel_user_id).first_or_create!
end

在我们的应用程序中随机产生一个ActiveRecord :: RecordNotUnique异常,
问题是:

is randomly causing an ActiveRecord::RecordNotUnique exception in our application, the issue is:


密钥的重复条目
'index_panel_user_offer_visits_on_offer_id_and_panel_user_id'

Duplicate entry for key 'index_panel_user_offer_visits_on_offer_id_and_panel_user_id'

我在rails doc上读过 first_or_create!不是一个原子方法,可能导致这种问题的高

I've read on the rails doc that first_or_create! is not an atomic method and can cause this kind of issues in a high concurrency environment and that a solution would be just to catch the exception and retry.

我尝试了不同的方法,包括 Retriable gem 重试一定次数,重复操作,但RecordNotUnique仍然提高。

I tried different approaches, including Retriable gem to retry a certain number of times to repeat the operation but RecordNotUnique is still raised.

我甚至尝试更改逻辑:

def get_offer_visit(offer_id, panel_user_id)
  begin
    offer_visit = PanelUserOfferVisit.where(:offer_id => offer_id, :panel_user_id => panel_user_id).first_or_initialize
    offer_visit.save!        
    offer_visit

  rescue ActiveRecord::RecordNotUnique
    offer_visit = PanelUserOfferVisit.where(:offer_id => offer_id, :panel_user_id => panel_user_id).first
    raise Exception.new("offer_visit not found") if offer_visit.nil?

    offer_visit
  end
end

代码仍然提出我做的自定义异常,我真的不明白如何可以无法创建在第一次尝试的记录,因为记录存在,但然后当它试图找到的记录,它不再找到它。

But the code still raise the custom exception I made and I really don't understand how it can fails to create the record on the first try because the record exists but then when it tries to find the record it doesn't find it again.

我错过了什么?

推荐答案

这里的问题是由于竞争条件。我没有找到Github的确切代码片段,但让我们说方法 find_or_create 是这样的(编辑:这里是代码):

If I understand properly your problem here is due to a race condition. I didn't found the exact piece of code from Github but lets say the method find_or_create is something like (edit: here is the code):

def first_or_create!(attributes = nil, &block)
  first || create!(attributes, &block)
end

你应该尝试解决比赛条件,使用乐观悲观锁定

You should try to solve the race conditions using optimistic or pessimistic locking

在自定义方法中实施锁定后,应该继续捕获可能的 NotUnique 异常,但尝试清除缓存或使用 uncached 阻塞之前,再次执行查找。

Once locking implemented within your custom method, you should continue capturing possible NotUnique exceptions but try to clean cache or use uncached block before to perform the find again.

这篇关于Rails:ActiveRecord:RecordNotUnique with first_or_create的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆