我正在使用Rails 4应用程序,该应用程序需要创建大量对象以响应来自其他系统的事件。当我在其中一个模型上调用ActiveRecord::RecordNotUnique
时,我在主键列上出现非常频繁的PG::UniqueViolation
错误(由create!
引起)。
我在SO上找到了其他答案,建议解救异常并调用retry
:
begin
TableName.create!(data: 'here')
rescue ActiveRecord::RecordNotUnique => e
if e.message.include? '_pkey' # Only retry primary key violations
log.warn "Retrying creation: #{e}"
retry
else
raise
end
end
虽然这似乎有所帮助,但对于已存在于数据库中的顺序ID(缩写日志条目),我仍然会收到吨 ActiveRecord::RecordNotUnique
错误:
WARN -- Retrying creation: PG::UniqueViolation: DETAIL: Key (id)=(3067) already exists.
WARN -- Retrying creation: PG::UniqueViolation: DETAIL: Key (id)=(3068) already exists.
WARN -- Retrying creation: PG::UniqueViolation: DETAIL: Key (id)=(3069) already exists.
WARN -- Retrying creation: PG::UniqueViolation: DETAIL: Key (id)=(3070) already exists.
它尝试的ID在3000-4000范围内,即使相关表格中有超过90000条记录。
为什么ActiveRecord或PostgreSQL会浪费这么多时间来尝试现有的ID?
原始异常(简化/删除的查询字符串):
{
"exception": "ActiveRecord::RecordNotUnique",
"message": "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint \"table_name_pkey\"\nDETAIL: Key (id)=(3023) already exists."
}
答案 0 :(得分:17)
我不确定它是怎么发生的,但事实证明该表的主键的PostgreSQL序列以某种方式重置或与表不同步:
SELECT nextval('table_name_id_seq');
-- 3456
SELECT max(id) FROM table_name;
-- 95123
我不得不重新启动表格的最后一个ID:
ALTER SEQUENCE table_name_id_seq RESTART 95124;
更新: 这里是一个Rake任务,用于重置带有PostgreSQL项目的Rails 4上大多数模型的ID序列:
desc 'Resets Postgres auto-increment ID column sequences to fix duplicate ID errors'
task :reset_sequences => :environment do
Rails.application.eager_load!
ActiveRecord::Base.descendants.each do |model|
unless model.attribute_names.include?('id')
Rails.logger.debug "Not resetting #{model}, which lacks an ID column"
next
end
begin
max_id = model.maximum(:id).to_i + 1
result = ActiveRecord::Base.connection.execute(
"ALTER SEQUENCE #{model.table_name}_id_seq RESTART #{max_id};"
)
Rails.logger.info "Reset #{model} sequence to #{max_id}"
rescue => e
Rails.logger.error "Error resetting #{model} sequence: #{e.class.name}/#{e.message}"
end
end
end
以下参考文献证明是有用的:
答案 1 :(得分:6)
您还可以使用rails console
重置表'table_name'的序列.list-item {
list-style-tyle: none;
display: inline-block;
padding: 15px 25px;
cursor: pointer;
border: 1px solid red;
transition: 0.3s all ease-in-out;
}
.list-item:hover {
background: red;
color: white;
}
.text-here {
position: relative;
top: 40px;
transition: 0.3s all ease-in-out;
opacity: 0;
padding-left: 40px;
}
(在rails 3.2,rails 5.0.1中测试)