【发布时间】:2016-02-26 17:03:32
【问题描述】:
我有一个场景,其中 2 个 db 连接可能同时运行 Model.find_or_initialize_by(params) 并引发错误:PG::UniqueViolation: ERROR: duplicate key value against unique constraint
我想更新我的代码,以便它可以正常地从中恢复。比如:
record = nil
begin
record = Model.find_or_initialize_by(params)
rescue ActiveRecord::RecordNotUnique
record = Model.where(params).first
end
return record
问题是在我的本地机器上没有一个很好/简单的方法来重现它,所以我不确定我的修复是否真的有效。
所以我想我会有点创意,并尝试连续调用 create 2 次(本地)这应该引发然后 PG::UniqueViolation: ERROR,然后我可以从中解救并确保一切都得到妥善处理。
但是我得到这个错误:PG::InFailedSqlTransaction: ERROR: current transaction is aborted, commands ignored until end of transaction block
即使我将所有内容包装在单独的事务块中,我也会收到此错误
record = nil
Model.transaction do
record = Model.create(params)
end
begin
Model.transaction do
record = Model.create(params)
end
rescue ActiveRecord::RecordNotUnique
end
Model.transaction do
record = Model.where(params).first
end
return record
我的问题:
- 优雅地处理我在本文开头提到的竞争条件的正确方法是什么?
- 如何在本地进行测试?
我想我可能在这里遗漏了一些简单的东西,但是已经晚了,也许我没有想得太清楚。
我正在运行 postgres 9.3 和 rails 4。
EDIT 结果发现 find_or_initialize_by 应该是 find_or_create_by ,而我得到的错误来自后来在执行过程中发生的实际保存调用。 #VeryTiredWhenIWroteThis
【问题讨论】:
-
查看相关stackoverflow.com/q/17267417/398670。收到错误后必须回滚,然后在新事务中重试。