繁体   English   中英

PostgreSQL JDBC getGeneratedKeys 返回所有列

[英]PostgreSQL JDBC getGeneratedKeys returns all columns

我最近在一个项目的后端从 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));
}

输出:

Col name: pathstart
Col name: fk_id_c
Col name: xpathid
Col name: firstnodeisroot

表的数据库签名(从 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
)

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

CREATE SEQUENCE configuration.configuration_xpath_id_seq
  INCREMENT 1
  MINVALUE 1
  MAXVALUE 9223372036854775807
  START 242
  CACHE 1
  OWNED BY configuration.configuration_xpath.xpathid;

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

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

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

大多数驱动程序通过在查询结束时使用自动生成的列添加RETURNING子句来支持getGeneratedKeys() PostgreSQL 返回所有字段,因为它具有RETURNING * ,它只返回所有列。 这意味着要返回生成的键,它不必查询系统表来确定要返回的列,这节省了网络往返(和查询时间)。

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

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

从字里行间看,你可以说这允许说'我不知道,或者工作量太大,所以所有列最好代表自动生成的键'

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

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

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

顺便说一句:Oracle 是(曾经?)更糟:默认情况下它返回行的ROW_ID ,您需要使用单独的查询从该行获取(生成的)值。

更新 - 接受的答案(由 Mark)正确解释了问题所在。 我的解决方案也有效,但这只是因为我在重新创建表时首先添加了 PK 列。 无论哪种方式,所有列都由getGeneratedKeys()返回。

经过一番研究,我设法找到了问题的可能原因。 之前说过,我在一个软件项目的开发过程中,已经从 MySQL 改成了 PostgreSQL。 对于此迁移,我已将 SQL 转储加载到 PostgreSQL 中。 除了迁移的表之外,我还创建了一些新表(使用 pgAdmin III 中的 GUI 向导)。 在仔细调查两个表(一个导入,一个创建)之间的差异后,我确定了两件事:

  1. MySQL 转储中的CREATE TABLE语句将 PK 转换为BIGINT NOT NULL ,而不是SERIAL 这导致自动生成的 PK 不再正常工作,尽管我在问这个问题之前解决了这个问题。

  2. 我通过添加新序列并将其链接起来“修复”的表工作得很好,但是 SQL 生成代码(由 pgAdmin III 自动生成,如原始问题所示)与制作的表不同在 PostgreSQL 中。

请注意,我的固定表完美地工作(编辑):我可以插入记录、更新记录和执行连接......基本上可以做任何事情。 主键自动生成并更新序列。 但是,JDBC 驱动程序(准确地说是 psotgresql-9.2-1003.jdbc4.jar)无法返回我生成的密钥(尽管这些表功能齐全)。

为了说明迁移表和创建表之间的区别,下面是我迁移添加的表的生成代码示例:

CREATE TABLE configuration.configuration_xpathitem
(
  xpathitemid serial NOT NULL,
  xpathid integer,
  fk_id_c integer,
  itemname text,
  index integer,
  CONSTRAINT pk_configuration_xpathitem PRIMARY KEY (xpathitemid),
  CONSTRAINT fk_configuration_xpathitem_configuration FOREIGN KEY (fk_id_c)
      REFERENCES configuration.configuration (id_c) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fk_configuration_xpathitem_configuration_xpath FOREIGN KEY (xpathid)
      REFERENCES configuration.configuration_xpath (xpathid) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

您可以在这里清楚地看到我的 PK 具有serial关键字,对于迁移(和固定)表,它是integer not null default ...

因此,我想可能是 PostgreSQL 的 JDBC 驱动程序无法找到 PK。 我已经阅读了@Mark 在他的回复中强调的规范,这让我认为这是驱动程序返回所有列的原因。 这让我相信驱动程序找不到 PK,因为我认为它正在寻找serial关键字。

所以为了解决这个问题,我转储了我的数据,删除了我的错误表并再次添加它们,这次是从头开始而不是使用 MySQL 转储中的 SQL 语句,然后重新加载我的数据。 这为我解决了这个问题。 我希望这可以帮助任何也被卡住的人。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM