Ruby on rails Rails:ActiveRecord:RecordNotUnique与第一个\u或\u创建

Ruby on rails Rails:ActiveRecord:RecordNotUnique与第一个\u或\u创建,ruby-on-rails,concurrency,Ruby On Rails,Concurrency,我的模型表中有以下索引: 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_use

我的模型表中有以下索引:

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异常, 问题是:

钥匙的重复输入 '索引\u面板\u用户\u报价\u访问\u报价\u id\u和\u面板\u用户\u id'

我在rails上读到了
first\u或\u create
不是一种原子方法,在高并发性环境中可能会导致此类问题,解决方案只是捕获异常并重试

我尝试了不同的方法,包括重试一定次数以重复该操作,但仍然引发RecordNotUnique

我甚至试图改变逻辑:

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
但是代码仍然引发了我所做的自定义异常,我真的不明白为什么它在第一次尝试时无法创建记录,因为该记录存在,但当它尝试查找该记录时,却无法再次找到它


我遗漏了什么?

您似乎正在为
PanelUserOfferVisit访问rails查询缓存。其中(…)。首先,rails刚刚执行了相同的SQL查询,它认为在请求期间结果将保持不变

ActiveRecord::Base.connection.clear\u query\u cache
在第二次调用db之前应该会有所帮助


您也不必
保存如果不是新记录,则记录?

如果我正确理解,您的问题是由于比赛条件造成的。我没有从Github中找到确切的代码片段,但假设方法
find\u或\u create
类似于(编辑:这里是):

您应该尝试使用或解决比赛条件


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

我也遇到过类似的问题,但根本原因与种族状况无关

使用
first\u或\u create,插入删除值中的周围空格,但选择不删除

因此,如果您尝试以下方法:

Users.where(email: 'user@mail.com ')
(注意字符串末尾的空格),生成的sql查询将是:

SELECT  "users".* FROM "users" WHERE "users"."email" = 'user@mail.com ' ORDER BY "users"."id";
INSERT INTO "users" ("email") VALUES ('user@mail.com');
这将导致找不到可能存在的记录,那么插入查询将是:

SELECT  "users".* FROM "users" WHERE "users"."email" = 'user@mail.com ' ORDER BY "users"."id";
INSERT INTO "users" ("email") VALUES ('user@mail.com');
如果记录具有以下内容,则会导致
ActiveRecord::RecordNotUnique
错误user@mail.com'因为电子邮件已经存在

关于你的问题,我没有足够的细节,所以这可能是无关的,但它可能会帮助其他人