首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >find_or_create与rails中的竞赛条件、理论与生产

find_or_create与rails中的竞赛条件、理论与生产
EN

Stack Overflow用户
提问于 2011-02-08 22:39:47
回答 3查看 1.2K关注 0票数 0

嗨,我有这段代码

代码语言:javascript
复制
class Place < ActiveRecord::Base
  def self.find_or_create_by_latlon(lat, lon)
    place_id = call_external_webapi
    result = Place.where(:place_id => place_id).limit(1)
    result = Place.create(:place_id => place_id, ... ) if result.empty? #!
    result
  end
end

然后我想做另一个模型或控制器

代码语言:javascript
复制
p = Post.new
p.place = Place.find_or_create_by_latlon(XXXXX, YYYYY) # race-condition
p.save

但是,如果执行的操作是创建的,而在生产过程中,Place.find_or_create_by_latlon的p.place为0,则获取数据需要花费太多的时间。

如何在执行p.save之前强制等待响应?谢谢你的建议

EN

回答 3

Stack Overflow用户

发布于 2011-02-09 01:24:12

你说得对,这是一种竞赛条件,通常是由双击表单上的submit按钮的人触发的。如果遇到错误,您可能做的是回滚。

代码语言:javascript
复制
result = Place.find_by_place_id(...) ||
  Place.create(...) ||
  Place.find_by_place_id(...)

有更优雅的方法来做这件事,但基本的方法在这里。

票数 1
EN

Stack Overflow用户

发布于 2013-03-21 13:54:38

我不得不处理一个类似的问题。在我们的后端中,如果用户不存在,则从令牌创建用户。在已经创建用户记录之后,将发送一个缓慢的API调用来更新用户信息。

代码语言:javascript
复制
def self.find_or_create_by_facebook_id(facebook_id)
  User.find_by_facebook_id(facebook_id) || User.create(facebook_id: facebook_id)
rescue ActiveRecord::RecordNotUnique => e
  User.find_by_facebook_id(facebook_id)
end

def self.find_by_token(token)
  facebook_id = get_facebook_id_from_token(token)

  user = User.find_or_create_by_facebook_id(facebook_id)

  if user.unregistered?
    user.update_profile_from_facebook
    user.mark_as_registered
    user.save
  end

  return user
end

策略的步骤是首先从create方法中删除缓慢的API调用(在我的例子中是update_profile_from_facebook)。因为操作花费的时间太长,所以当您将操作作为创建调用的一部分时,会显著增加重复插入操作的机会。

第二步是向数据库列添加唯一约束,以确保不创建重复项。

最后一步是创建一个函数,在将重复插入操作发送到数据库的罕见情况下捕获RecordNotUnique异常。

这可能不是最优雅的解决方案,但它对我们有效。

票数 0
EN

Stack Overflow用户

发布于 2017-02-11 21:28:06

我在一个助手作业中按了这个键,它会反复地重试并得到错误,并最终清除它自己。我找到的最好的解释是在博客这里上找到的。要点是postgres保留了一个内部存储的值,用于增加被弄乱的主键。这对我来说是真的,因为我正在设置主键,而不仅仅是使用一个递增的值,所以这很可能是这样出现的。上面链接中的注释中的解决方案似乎是调用ActiveRecord::Base.connection.reset_pk_sequence!(table_name),这为我解决了这个问题。

代码语言:javascript
复制
begin
   result = Place.where(:place_id => place_id).limit(1)
   result = Place.create(:place_id => place_id, ... ) if result.empty? #!
rescue ActiveRecord::StatementInvalid => error
   @save_retry_count =  (@save_retry_count || 1)
   ActiveRecord::Base.connection.reset_pk_sequence!(:place)
   retry if( (@save_retry_count -= 1) >= 0 )
   raise error
end
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4939349

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档