本文介绍了find_or_create竞赛条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用ActiveRecord的 c归因于其迁移,所以Postgres会知道我是认真的。

I'm trying to use ActiveRecord's find_or_create_by_*column*, but I'm getting errors from Postgres letting me know that it occasionally fails to find the model, and tries to insert one anyways. It's really important that I keep this table unique, so I added a :unique => true attribute to its migration, so that Postgres would know that I was serious about it.

而且,失败:

ActiveRecord :: StatementInvalid:PGError:错误:重复键值违反了唯一约束 index_marketo_leads_on_person_id详细信息:键(person_id)=(9968932)已存在。 :插入 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电子邮件服务器,并保留上次修改用户某些字段的记录,以便我们可以在批处理后台任务中推送更改的记录。

The second model is used for linking our users accounts to the Marketo email server, and keeping a record of the last time certain fields of the user was modified, so that we can push changed records in batched background tasks.

我想不出该回调的任何原因, update_marketo_lead 失败,除了某种竞赛我无法想象的情况。

I can't think of any reason for this callback, update_marketo_lead to fail, other than some kind of race condition that I can't quite imagine.

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

(please ignore the horribleness of 'user' sharing a primary key with 'person')(using Rails 2.3.11, Postgres 9.0.3)

推荐答案

很有可能在执行find_or_create时没有找到匹配的person_id,因此使用了create逻辑,但是在find_or_create和实际的user.save,另一个请求成功完成了保存事务,这时您的数据库约束导致了此异常。

Its quite possible that when find_or_create was executed, matching person_id was not found, so create logic was used, however its possible that between find_or_create and actual user.save, another request managed to complete save transaction and at that point your Database constraint caused this exception.

我建议您捕获StatementInvalid异常,并重试保存(最多有限次数...

What I would recommend is to catch StatementInvalid exception and to retry saving(up to a finite number of times...

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

请注意,此操作应在您尝试保存用户的任何位置执行。 HAP内保存保存!交易

Note this should be executed wherever you try to save the user. All callbacks and validations are happening within save! transaction

P.S。我假设您的Rails版本支持事务:)在Rails 3中,不需要包装保存!在交易中,因为它已经在内部使用了

P.S. Im assuming your version of rails supports transactions :) In Rails 3 its unnecessary to wrap save! in transaction because it already uses one internally

这篇关于find_or_create竞赛条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-22 17:21