问题描述
我正在尝试使用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竞赛条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!