无法使用 PreparedStatement 的 getGeneratedKeys() 在 Java 中找到生成的密钥

Posted

技术标签:

【中文标题】无法使用 PreparedStatement 的 getGeneratedKeys() 在 Java 中找到生成的密钥【英文标题】:Unable to find a generated key in Java using PreparedStatement's getGeneratedKeys() 【发布时间】:2012-04-17 10:23:11 【问题描述】:

我有一个查询如下:

String SQL = "insert into table (id, name) values (sequence.nextval, ?)";

然后我制作一个这样的 PreparedStatement:

//initiate connection, statement etc
pStatement = connection.prepareStatement(SQL, Statement.RETURN_GENERATED_KEYS);
pStatement.setString(1,'blabla');

pStatement.executeUpdate();
ResultSet rs = pStatement.getGeneratedKeys();

while (rs.next())
  //debugging here to see what rs has

在该调试点执行和调试时,我看到我的 ResultSet 只有一个键,一个字符串 - 根本不像我期望的 id。检查数据库时一切正常,id 被插入,一切正常。 getGeneratedKeys(); 有一些东西 这让我很困惑。

我做错了什么?

提前致谢

【问题讨论】:

您没有使用“生成的密钥”,您只是在 INSERT 语句中使用了生成器。 getGeneratedKeys() 用于返回由数据库生成的键,作为 INSERT 的一部分(通过标识列或通过触发器)。 【参考方案1】:

我希望您返回的看起来像字符串的“键”是ROWID——这是数据库直接生成的唯一键。您应该能够更改它以恢复您的 id 列(这可能需要 JDBC 驱动程序的较新版本)。

//initiate connection, statement etc
String generatedColumns[] = "ID";
pStatement = connection.prepareStatement(SQL, generatedColumns);
pStatement.setString(1,'blabla');

pStatement.executeUpdate();
ResultSet rs = pStatement.getGeneratedKeys();

while (rs.next())
  //debugging here to see what rs has

您还可以更改查询以显式添加RETURNING 子句

String SQL = "insert into table (id, name) " + 
             "  values (sequence.nextval, ?) " + 
             "  returning id into ?";

【讨论】:

谢谢。我选择了您的第一个选项来包含 generateColumns。事实上,我的 ResultSet 首先给了我一些我不理解的行,但现在我传递 string[] "id" 返回新生成的 id。【参考方案2】:

如果这不起作用,则问题可能出在 sequence.nextval 上。如果您正在使用它,您似乎并没有在技术上自动生成密钥

【讨论】:

【参考方案3】:

我很确定getGeneratedKeys 不会返回使用序列的下一个值初始化的键的值。实际上,在这种情况下,数据库不会自己生成密钥(就像使用自动增量列一样)。

如果你想知道生成的密钥,那么执行第一个查询:

select sequence.nextval from dual

然后使用第一个查询的结果来执行你准备好的语句:

insert into table (id, name) values (?, ?)

【讨论】:

【参考方案4】:

我认为:

pStatement.setString('blabla');

应该是:

pStatement.setString(1, 'blabla');

希望对你有帮助。

【讨论】:

对不起 - 你是对的。这是我的错,因为我没有在此处复制粘贴我的代码,而是尝试以更一般的术语键入示例以使代码更易于阅读。但是,在我的代码中,我做得正确。所以虽然你是对的,但这不是我正在努力解决的问题。我已经编辑了我的帖子。 @arnehehe 你是对的,你可以编译你的代码,所以这不是错误。我的错。【参考方案5】:

您的代码有一个错误:由于您使用的是 PreparedStatement,您应该使用它自己的RETURN_GENERATED_KEYS 常量:

pStatement = connection.prepareStatement(SQL, PreparedStatement.RETURN_GENERATED_KEYS);

getGeneratedKeys() 函数应该可以正常执行,并且您应该能够获取在ResultSet 变量中生成的密钥。

通过这种方式,您无需为行指定任何名称(正如 Justin 解决方案所建议的那样,这非常好)。如果您使用以下方式访问检索到的键,则只需指定您的行名:

id = rs.getInt("id_row_name");

代替:

id = rs.getInt(column_number); //One column for each key retrieved.

【讨论】:

以上是关于无法使用 PreparedStatement 的 getGeneratedKeys() 在 Java 中找到生成的密钥的主要内容,如果未能解决你的问题,请参考以下文章

即使明确设置 PreparedStatement 也不会超时

PreparedStatement 最大查询,参数未在 Java 中执行

选择计数的 PreparedStatement [重复]

PreparedStatement 使用like 模糊查询

使用 PreparedStatement 进行批处理

PreparedStatement 和 Statment区别