加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby-on-rails – find_or_create竞争条件

发布时间:2020-12-17 03:12:52 所属栏目:百科 来源:网络整理
导读:我正在尝试使用ActiveRecord的find_or_create_by_ *列*,但是我从Postgres得到错误让我知道它偶尔找不到模型,并试图插入一个.我保持这个表的独特性非常重要,所以我添加了一个:unique =这是其迁移的真正属性,因此Postgres会知道我对此很认真. 并且,失败: Act
我正在尝试使用ActiveRecord的find_or_create_by_ *列*,但是我从Postgres得到错误让我知道它偶尔找不到模型,并试图插入一个.我保持这个表的独特性非常重要,所以我添加了一个:unique =>这是其迁移的真正属性,因此Postgres会知道我对此很认真.

并且,失败:

ActiveRecord :: StatementInvalid:PGError:ERROR:重复键值违反唯一约束“index_marketo_leads_on_person_id”DETAIL:键(person_id)=(9968932)已存在. :INSERT INTO“marketo_leads”(“mkt_person_id”,“synced_at”,“person_updated_at”,“person_id”)VALUES(NULL,NULL,’2011-05-06 12:57:02.447018′,9968932)返回“id”

我有这样的模型:

class User < AR::Base
  has_one :marketo_lead

  before_save :update_marketo_lead

  def update_marketo_lead
    if marketo_lead
      if (User.marketo_columns & self.changes.keys).any?  
        marketo_lead.touch(:person_updated_at) 
      end
    elsif self.id
      marketo_lead = MarketoLead.find_or_create_by_person_id(:person_updated_at => Time.now,:person_id => self.id) 
    end
  end
end

class MarketoLead
  belongs_to :user,:foreign_key => 'person_id'
end

第二个模型用于将我们的用户帐户链接到Marketo电子邮件服务器,并保留上次更改用户的某些字段的记录,以便我们可以在批量后台任务中推送更改的记录.

我无法想到这个回调的任何原因,update_marketo_lead失败,除了某些我无法想象的竞争条件.

(请忽略’用户’与’人’共享主键的可怕性)
(使用Rails 2.3.11,Postgres 9.0.3)

解决方法

很可能当执行find_or_create时,找不到匹配的person_id,因此使用了create logic,但是它可能在find_or_create和实际user.save之间,另一个请求设法完成保存事务,此时你的数据库约束导致了这个异常.

我建议的是捕获StatementInvalid异常并重试保存(最多有限次数…

begin
   user.save!
rescue ActiveRecord::StatementInvalid => error
  @save_retry_count =  (@save_retry_count || 5)
  retry if( (@save_retry_count -= 1) > 0 )
  raise error
end

请注意,这应该在您尝试保存用户的任何位置执行.所有回调和验证都在保存中发生!交易

附:我假设您的rails版本支持事务:)在Rails 3中,它不需要包装保存!在事务中因为它已经在内部使用了一个

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读