【问题标题】:multiple insert with sequence fails in Postgres在 Postgres 中多次插入序列失败
【发布时间】:2015-03-24 13:47:26
【问题描述】:

有一个带有多个值的插入查询(大约 18k):

INSERT INTO ENTRIES (ID, USER_ID) 
VALUES (nextval('my_seq'), '233'),(nextval('my_seq'), '233');

这是从 Java 应用程序中的 liquibase 变更集触发的:

JdbcConnection connection = (JdbcConnection) database.getConnection();

        ResultSet resultSet = connection.prepareStatement("SELECT ID FROM USERS").executeQuery();

        List<String> values = new ArrayList<>();

        while (resultSet.next()) {
            Long userId = resultSet.getLong(1);

            for (int i = 0; i < 3; i++) {
                values.add("(nextval('my_seq'), '" + userId + "')");
            }
        }

        String sql = "INSERT INTO ENTRIES (ID, USER_ID) VALUES " + join(values, ",") + ";";

        connection.createStatement().execute(sql);

当它针对 h2 数据库执行时,一切都很好,但是当我针对 postgres 运行它时,会抛出以下异常:

duplicate key value violates unique constraint "entries_pkey"

序列中的like id 正在被重复使用。

在 pgAdmin 中运行 sql 时一切正常,但从应用程序中它在第一次插入时失败。

我的第一个想法是,也许 sql 应该以不同的方式执行。

对此有什么想法吗?

这是表格说明:

  CREATE TABLE entries
(
  id bigint NOT NULL,
  user_id bigint,
  CONSTRAINT entries_pkey PRIMARY KEY (id),
  CONSTRAINT fk_e3udjwux3ly7lu31huish0f82 FOREIGN KEY (user_id)
      REFERENCES users (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)
WITH (
  OIDS=FALSE
);
ALTER TABLE entries
  OWNER TO app;

【问题讨论】:

  • 能贴出entrys表的定义吗?
  • 为什么不对 ID 字段使用默认值?让数据库处理增量就可以了,您不必再在 INSERT 语句中提及此字段了。
  • @FrankHeikens 在默认情况下使用 nextval 时会出现同样的错误。
  • 条目表的主键是什么?是否可以简单地使用INSERT INTO entries (id, user_id) ( SELECT nextval('my_seq'), id FROM users)
  • 当你得到同样的错误时,你的序列不是最新的:这个序列生成的值已经被使用了。检查表中的 max(id) 和序列的当前值。

标签: java sql postgresql liquibase


【解决方案1】:

我的猜测是您的序列计数器需要重置(也许您在表格中手动输入了数字,而不是使用 nextval,因此计数器没有增加),并且它给出了您表格中已有的数字。尝试用类似的东西重置它

ALTER SEQUENCE my_seq RESTART 100000;

其中 100000 是大于:

SELECT MAX(id) FROM entries;

【讨论】:

  • 问题是它发生在空表上,仅使用该插入查询插入数据。所以这是不可能的。
  • sandris,抱歉错过了阅读该部分。你的 jdbc 代码,我记得的 jdbc 看起来不错(如果是整数,则不应引用 user_id)。虽然这不会引起您的问题。
【解决方案2】:

根据经验,如果您的 dbms 可以自动执行某项操作,则不应尝试自己执行。

CREATE TABLE entries
(
  -- bigserial provides automatic sequence numbers under
  -- dbms control.
  id bigserial NOT NULL,
  user_id bigint,
  CONSTRAINT entries_pkey PRIMARY KEY (id),
  CONSTRAINT fk_e3udjwux3ly7lu31huish0f82 FOREIGN KEY (user_id)
      REFERENCES users (id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
);

插入此表,根本不提及“id”。

INSERT INTO ENTRIES (USER_ID) 
VALUES ('233'),('233');

或者使用“默认”值。

INSERT INTO ENTRIES (ID, USER_ID) 
VALUES (default, '233'),(default, '233');

在这种情况下,default 不是字符串。 (没有引号。)

【讨论】:

    【解决方案3】:

    代码是正确的,问题在于序列的大小 - 对于 18k 插入来说太小了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-27
      • 2018-09-03
      • 1970-01-01
      • 2020-08-05
      • 2017-08-27
      • 2019-11-24
      相关资源
      最近更新 更多