首页 > 解决方案 > 带有 SEQUENCE 的 PostgreSQL“重复键违规”

问题描述

[问题已解决。请参阅下面的答案。]

我刚刚遇到了一系列“重复键值违反唯一约束”的错误,该系统已经运行了几个月。我无法确定它们发生的原因。

这是错误:

org.springframework.dao.DuplicateKeyException: PreparedStatementCallback;
SQL [
INSERT INTO transaction_item 
  (transaction_group_id, transaction_type, start_time, end_time) VALUES 
  (?, ?::transaction_type_enum, ?, ?)
];
ERROR: duplicate key value violates unique constraint "transaction_item_pkey"
  Detail: Key (transaction_id)=(67109) already exists.;

以下是相关 SEQUENCE 和 TABLE 的定义:

CREATE SEQUENCE transaction_id_seq AS bigint;

CREATE TABLE transaction_item (
  transaction_id bigint PRIMARY KEY DEFAULT NEXTVAL('transaction_id_seq'),
  transaction_group_id bigint NOT NULL,
  transaction_type transaction_type_enum NOT NULL,
  start_time timestamp NOT NULL,
  end_time timestamp NOT NULL
);

这是用于插入该表的唯一 SQL 语句:

INSERT INTO transaction_item
  (transaction_group_id, transaction_type, start_time, end_time) VALUES 
  (:transaction_group_id, :transaction_type::transaction_type_enum, :start_time, :end_time)

如您所见,我没有明确尝试设置 transaction_id 的值。我已经为列定义定义了一个默认值,并使用它从 SEQUENCE 中获取一个值。

我一直认为上述方法是安全的,即使在高并发情况下使用也是如此。一个 SEQUENCE 不应该两次返回相同的值,对吧?

我真的很感激一些帮助,以了解为什么会发生这种情况,以及如何解决它。谢谢!

标签: postgresqlpostgresql-12

解决方案


我找到了这个问题的原因。

几个月前(在这个系统的开发过程中)发现了一个问题,这意味着有必要从数据库中清除任何现有的测试数据。我对所有 TABLES 使用 DELETE FROM 语句,对所有 SEQUENCES 使用 ALTER ... RESTART 语句。这些语句已添加到 Liquibase 配置中,以便在新代码启动期间执行。从当时检查日志来看,系统的一个实例似乎在迁移时仍在运行。这发生了:系统的新实例删除了 TRANSACTION_ITEM 表中的所有数据,仍在运行的实例随后向该表添加了更多数据,然后新实例重新启动了用于插入这些记录的 SEQUENCE 使用。所以昨天,当我收到重复的密钥违规时,

说来话长,但现在一切都说得通了。感谢那些对此问题发表评论的人。


推荐阅读