【问题标题】:Retrieving serial id from batch inserted rows in postgresql从postgresql中的批量插入行中检索序列号
【发布时间】:2013-04-13 17:03:39
【问题描述】:

这是有效的代码:

        Connection c = ds.getConnection();
        c.setAutoCommit(false);
        PreparedStatement stmt = c.prepareStatement("INSERT INTO items (name, description) VALUES(?, ?)");
        while (!(items = bus.take()).isEmpty()) {
          for (Item item : items) {
            stmt.setString(1, item.name);
            stmt.setString(2, item.description);
            stmt.addBatch();
          }
          stmt.executeBatch();
          c.commit();
        }

但是现在我需要填充另一个表,其中 id 是外键。 如果我将 INSERT 与 RETURNING id 一起使用,则 executeBatch 将失败,并出现“预期没有结果时返回结果”错误。

我看到了几种解决方法

  • 单独插入而不是批量插入。
  • 将序列号替换为客户端生成的 guid。
  • 使用某种存储过程来执行批量插入并返回 ID 列表。

在我看到的三种方法中,最后一种似乎既保留了批量插入的效率又保留了返回 id,但它对我来说也是最复杂的,因为我从未编写过存储过程。

有没有更好的方法来批量插入和获取 ID?我使用 postgresql 特定的 API 而不是 jdbc 没有问题。

如果没有,任何人都可以画出这样的存储过程吗?

这是表架构:

CREATE UNLOGGED TABLE items
(
  id serial,
  name character varying(1000),
  description character varying(10000)
)
WITH (
  OIDS=FALSE
);

【问题讨论】:

  • 看看 JDBC getGeneratedKeys 方法。不过,我还没有专门验证它是否适用于批量连接。
  • 用 wCTE 一次填充两个表怎么样?
  • @JakubKania - wCTE 是什么?你能举个例子吗?
  • @mark 一个可写的 CTE,它可以让你像这样链接查询。看这里:depesz.com/2011/03/16/waiting-for-9-1-writable-cte 这是 9.1+ 的功能。
  • @mark 对此有何更新?

标签: java postgresql jdbc batch-file


【解决方案1】:

这样的事情应该可以工作:

// tell the driver you want the generated keys
stmt =  c.prepareStatement("INSERT ... ", Statement.RETURN_GENERATED_KEYS);

stmt.executeBatch();

// now retrieve the generated keys
ResultSet rs = stmt.getGeneratedKeys();
while (rs.next()) {
 int id = rs.getInt(1);
 .. save the id somewhere or update the items list 
}

我认为(我不确定确定!)密钥按照生成的顺序返回。因此,ResultSet 中的第一行应该映射到您正在处理的列表中的第一个“项目”。但请务必确认!

编辑

如果这不起作用,请尝试指定为其生成值的实际列:

stmt =  c.prepareStatement("INSERT ... ", new String[] {"id"});

【讨论】:

  • @mark:您需要在准备语句时告诉驱动程序返回这些值。查看我的编辑。
  • 好的,这行得通。但是有些东西留下了。您听起来不确定第一行是否映射到第一个返回的 id。 docs.oracle.com/javase/1.4.2/docs/guide/jdbc/getstart/… 的文档也没有说明这一点。然而,这是一个至关重要的信息。如果没有此保证,该功能将毫无用处。至少对于 postgresql 有保证吗?
  • @mark:正如我所说:我不知道。你需要自己测试一下。
  • 我测试了它,但它什么也没证明。它在我的开发环境中工作的事实并不能说明它是否会在生产环境中工作。我们需要一些来自 postgresql 大师的权威答案。但我会将您的回复视为答案。
  • 请看postgresql.org/message-id/flat/…,我在邮件列表上问过这个问题。目前看来订单显然得到保证。你把一些代码建立在预期的基础上,这是在玩火。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多