从postgresql中的批处理插入行中检索序列ID

mar*_*ark 6 java postgresql jdbc batch-file

这是有效的代码:

        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();
        }
Run Code Online (Sandbox Code Playgroud)

但现在我需要填充另一个表,其中id是外键.如果我使用INSERT RETURNING id然后executeBatch失败并且"当没有预期时返回结果"错误.

我看到了解决这个问题的几种方法

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

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

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

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

这是表模式:

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

a_h*_*ame 10

这样的事情应该有效:

// 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 
}
Run Code Online (Sandbox Code Playgroud)

我认为(我肯定!),该密钥在生成它们的顺序返回.因此,ResultSet中的第一行应映射到您正在处理的列表中的第一个"项".但要确认一下!

编辑

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

stmt =  c.prepareStatement("INSERT ... ", new String[] {"id"});
Run Code Online (Sandbox Code Playgroud)

  • 请查看https://www.postgresql.org/message-id/flat/36689061-0844-2dfd-a4ee-8006d8a15ca9%40gmail.com,我在邮件列表上提出了问题。看来目前订单显然“无法”得到保证。如果你根据预期编写一些代码,那么你就是在玩火。 (3认同)
  • 好的,那行得通。但是还剩下一些东西。您听起来不确定第一行是否映射到第一个返回的 id。http://docs.oracle.com/javase/1.4.2/docs/guide/jdbc/getstart/preparedstatement.html 上的文档也没有说明这一点。然而,这是一条至关重要的信息。没有这个保证,这个功能就毫无用处。是否有保证,至少对于 postgresql? (2认同)