PostgreSQL JDBC getGeneratedKeys返回所有列

War*_*kst 4 java postgresql jdbc

我最近从MySQL切换到PostgreSQL用于项目的后端,并发现了我需要检查的一些数据库代理方法.要插入链接对象,我使用事务来确保存储所有内容.我这样做使用jdbc方法,如setAutoCommit(false)commit().我编写了一个实用工具方法,将记录插入表中并返回生成的密钥.基本上我按照这里描述的技术2:

http://www.selikoff.net/2008/09/03/database-key-generation-in-java-applications/

这从项目开始以来一直有效,但是从MySQL迁移到PostgreSQL之后会getGeneratedKeys返回新插入记录的所有列(请参阅下面的控制台输出).

码:

final ResultSet keys = ps.getGeneratedKeys();
final ResultSetMetaData metaData = keys.getMetaData();
for (int j = 0; j < metaData.getColumnCount(); j++) {
    System.out.println("Col name: "+metaData.getColumnName(j+1));
}
Run Code Online (Sandbox Code Playgroud)

输出:

Col name: pathstart
Col name: fk_id_c
Col name: xpathid
Col name: firstnodeisroot
Run Code Online (Sandbox Code Playgroud)

表的数据库签名(从pgAdmin III自动生成的SQL):

CREATE TABLE configuration.configuration_xpath
(
  pathstart integer NOT NULL,
  fk_id_c integer NOT NULL,
  xpathid integer NOT NULL DEFAULT nextval('configuration.configuration_xpath_id_seq'::regclass),
  firstnodeisroot boolean NOT NULL DEFAULT false,
  CONSTRAINT configuration_xpath_pkey PRIMARY KEY (xpathid),
  CONSTRAINT configuration_fk FOREIGN KEY (fk_id_c)
      REFERENCES configuration.configuration (id_c) MATCH SIMPLE
      ON UPDATE CASCADE ON DELETE CASCADE
)
Run Code Online (Sandbox Code Playgroud)

PK背后序列的数据库签名:

CREATE SEQUENCE configuration.configuration_xpath_id_seq
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 242
  CACHE 1
  OWNED BY configuration.configuration_xpath.xpathid;
Run Code Online (Sandbox Code Playgroud)

所以问题是,为什么getGeneratedKeys返回所有列而不仅仅是生成的键?我在这里搜索并发现了其他有类似问题的人:

http://www.postgresql.org/message-id/004801cb7518$cbc632e0$635298a0$@pravdin@disi.unitn.it

但他们的问题尚未得到解答,只提供了建议的解决方法.

Mar*_*eel 7

大多数驱动程序getGeneratedKeys()通过RETURNING使用自动生成的列在查询末尾添加-clause来支持.PostgreSQL返回所有字段,因为它只RETURNING *返回所有列.这意味着要返回生成的密钥,它不必查询系统表来确定要返回的列,这样可以节省网络往返(和查询时间).

这是JDBC规范隐式允许的,因为它:

注意:如果未指定表示自动生成的键的列,则JDBC驱动程序实现将确定最能代表自动生成的键的列.

在行之间阅读,你可以说这可以说'我不知道,或者它是太多的工作,所以所有列最能代表自动生成的密钥'.

另一个原因可能是很难确定哪些列是自动生成的,哪些不是(我不确定PostgreSQL是否属实).例如,在Jaybird(我维护的Firebird的JDBC驱动程序)中,我们也返回所有列,因为在Firebird中无法确定哪些列是自动生成的(但我们确实需要在系统表中查询列名,因为Firebird会没有RETURNING *).

因此,始终建议ResultSet按列名称而不是按位置显式查询生成的键.

其他解决方案是使用接受a String[]或的替代方法显式指定要返回的列名或列位置int[](尽管我不是100%确定PostgreSQL驱动程序如何处理).

BTW:Oracle更糟糕了:默认情况下,它会返回ROW_ID行的行,并且您需要使用单独的查询来从该行获取(生成的)值.