Java PostgreSQL JDBC getGeneratedKeys返回所有列
我最近在一个项目的后端从MySQL切换到PostgreSQL,发现我的一些数据库代理方法需要检查。要插入链接对象,我使用事务来确保所有内容都已存储。我使用jdbc方法来实现这一点,比如Java PostgreSQL JDBC getGeneratedKeys返回所有列,java,postgresql,jdbc,Java,Postgresql,Jdbc,我最近在一个项目的后端从MySQL切换到PostgreSQL,发现我的一些数据库代理方法需要检查。要插入链接对象,我使用事务来确保所有内容都已存储。我使用jdbc方法来实现这一点,比如setAutoCommit(false)和commit()。我编写了一个实用方法,它将记录插入表中并返回生成的键。基本上我遵循了这里描述的技术2: 这在项目开始时就起作用了,但是在从MySQL迁移到PostgreSQL之后,getGeneratedKeys返回新插入记录的所有列(请参见下面的控制台输出) 代码:
setAutoCommit(false)
和commit()
。我编写了一个实用方法,它将记录插入表中并返回生成的键。基本上我遵循了这里描述的技术2:
这在项目开始时就起作用了,但是在从MySQL迁移到PostgreSQL之后,getGeneratedKeys
返回新插入记录的所有列(请参见下面的控制台输出)
代码:
表的数据库签名(由pgAdmin III自动生成的SQL):
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
返回所有列,而不仅仅是生成的键?我在这里搜索并找到了其他有类似问题的人:
但是他们的问题没有得到回答,只提供了一个建议的解决方法。大多数驱动程序支持
getGeneratedKeys()
,方法是在查询末尾添加一个RETURNING
-子句,其中包含自动生成的列。PostgreSQL返回所有字段,因为它有RETURNING*
,只返回所有列。这意味着要返回生成的键,它不必查询系统表来确定要返回的列,这节省了网络往返(和查询时间)
这是JDBC规范隐含允许的,因为它:
注意:如果未指定表示自动生成键的列,JDBC驱动程序实现将确定最能表示自动生成键的列
在字里行间,你可以说这允许说“我不知道,或者这是太多的工作了,所以所有的列最好代表自动生成的键”
另一个原因可能是很难确定哪些列是自动生成的,哪些不是(我不确定PostgreSQL是否是这样)。例如,在Jaybird(我维护的Firebird的JDBC驱动程序)中,我们还返回所有列,因为在Firebird中,无法确定哪些列是自动生成的(但我们确实需要查询系统表中的列名,因为Firebird 3和更早版本没有返回*
)
因此,始终建议按列名而不是位置显式查询生成的键ResultSet
其他解决方案是使用接受or的替代方法显式指定要返回的列名或列位置(尽管我不能100%确定PostgreSQL驱动程序如何处理)
顺便说一句:Oracle更糟糕:默认情况下,它返回该行的
行ID
,您需要使用单独的查询从该行获取(生成的)值。更新-接受的答案(按标记)正确地解释了问题所在。我的解决方案也有效,但这只是因为我在重新创建表时首先添加了PK列。无论哪种方式,所有列都由getGeneratedKeys()
返回
经过一些研究,我终于找到了问题的可能原因。正如我之前所说,在软件项目的开发过程中,我从MySQL改为PostgreSQL。对于这次迁移,我采用了一个SQL转储,并将其加载到PostgreSQL中。除了迁移的表之外,我还创建了一些新表(使用pgAdmin III中的GUI向导)。在仔细调查了两个表(一个导入,一个创建)之间的差异后,我确定了两件事:
CREATE TABLE
语句将PKs转换为BIGINT NOT NULL
,而不是SERIAL
。这导致自动生成的PKs不再正常工作,尽管我在问这个问题之前已经解决了这个问题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语句,然后重新加载了数据。这为我解决了问题。我希望这能帮助那些同样陷入困境的人。谢谢你的回复。虽然你说的是真的,但这不是问题的原因。我已经用不同的postgresql数据库创建了一个测试环境,在那里一切正常。我已经能够定位并同时解决问题
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
)
CREATE SEQUENCE configuration.configuration_xpath_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 242
CACHE 1
OWNED BY configuration.configuration_xpath.xpathid;
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
)