修复不存在唯一约束违规时的PG::UniqueViolation错误
你是否曾经在确定没有重复数据的情况下遇到PG::UniqueViolation错误?罪魁祸首通常是不同步的PostgreSQL序列。
问题
你看到这样的错误:
PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "users_pkey"
DETAIL: Key (id)=(42) already exists.
但当你检查时,并没有ID为42的记录。发生了什么?
原因
PostgreSQL使用序列来生成自增ID。有时,特别是在数据导入或手动插入之后,序列会与表中实际的最大ID不同步。
解决方法
将序列重置为正确的值:
SELECT setval('users_id_seq', (SELECT MAX(id) FROM users));
或者在Rails中:
ActiveRecord::Base.connection.execute(
"SELECT setval('users_id_seq', (SELECT MAX(id) FROM users))"
)
对于所有表
一次性修复所有序列:
ActiveRecord::Base.connection.tables.each do |table|
ActiveRecord::Base.connection.reset_pk_sequence!(table)
end
预防
此问题通常发生在以下情况之后:
- 数据迁移或导入
- 使用显式ID进行手动SQL插入
- 从备份恢复
始终在批量数据操作后重置序列,以避免这些神秘的错误。