getGeneratedKeys() returns 一个空结果集

getGeneratedKeys() returns an Empty ResultSet

你好,感谢阅读。 我正在尝试检索新插入数据的 ID,但我总是得到一个空的结果集。

 Connection con = main.getCon();
 String sqlCommand = "Insert Into Relations(name,explanation) values(?,?)";
 PreparedStatement state = 
 con.prepareStatement(sqlCommand,Statement.RETURN_GENERATED_KEYS);
 state.setString(1,name.getText());
 state.setString(2,explanation.getText());
 int affectedRows = state.executeUpdate();
 assert (affectedRows>0);
        
 ResultSet rs = state.getGeneratedKeys();
 assert rs.next();
 int instertedID= rs.getInt("ID");

不确定它有什么问题。在线检查了不同的样本,但无法弄清楚我的错误是什么。 我也用 Statement 试过,但也没成功。
第 1 点:代码运行顺利,我的数据已插入数据库。 第2点:网上有这种情况的例子,你可以在这里查看: https://www.baeldung.com/jdbc-returning-generated-keys

我刚刚意识到我的 ResultSet 不是空的,我在使用调试器时遇到了问题,这就是为什么我认为它是空的。 正如 Mark Rotteveel 在评论中提到的,问题出在“断言”语句上。

这取决于数据库引擎。一些提示:

JDBC 是 low-level,不适合用

编程

这很复杂 API。使用使它更容易的东西:JDBI 或 JOOQ。他们可能对插入有抽象,可以为您处理这些事情。

一些数据库引擎要求您列出列名

尝试:

con.prepareStatement(sqlCommand, new String[] {"UNID"});

一些数据库引擎只会return生成值作为直接结果集

不要打电话.executeUpdate();相反,调用 .executeQuery() 其中 return 是 ResultSet;检查那个。

其他

Post 如果以上没有帮助,您正在使用的确切 table 结构和数据库引擎。

您的代码已损坏

您不能创建资源对象(一旦 必须 关闭)除非您这样做是安全的,而您这样做并不安全。使用 try-with-resources:

String sql = "INSERT INTO relations(name, explanation) VALUES (?, ?)";
try (Connection con = main.getCon();
    PreparedStatement ps = con.prepareStatement(sql, new String[] {"unid"})) {

    state.setString(1, name.getText());
    state.setString(2, explanation.getText());
    try (ResultSet rs = state.executeQuery()) {
        if (!rs.next()) throw new SQLException("insert didn't return autogen?");
        System.out.println(rs.getInt(1));
    }
}

ResultSets、Statements、PreparedStatements 和 Connections 都是资源(必须关闭!)- 如果您想将这些东西之一存储在一个字段中,您可以这样做,但前提是 class包含这个字段本身就是一个资源:它必须有一个 close() 方法,它必须实现 AutoClosable,然后你只能像上面那样用 try-with-resources 创建这个 class 的实例。

未能遵守这些规则意味着您的应用似乎可以正常工作,但在 运行 时会泄漏资源,因此,如果您让它 运行 时间足够长,它就会开始崩溃。此外,随着越来越多的连接保持打开状态,您的数据库引擎将逐渐停止,永远卡住。

将最后一行代码更改为此,因为您使用的 DBMS 可能不支持按列名获取值,因此传递该列的索引:

int instertedID = rs.getInt(1); 
String sqlCommand = "Insert Into Relations (name, explanation) values(?, ?)";
PreparedStatement state = con.prepareStatement(sqlCommand, Statement.RETURN_GENERATED_KEYS);
 state.setString(1,name.getText());
 state.setString(2,explanation.getText());
 state.executeUpdate();
 

ResultSet resultSet = state.getGeneratedKeys();

if(resultSet.next()) {
    System.out.println(resultSet.getInt(1)); //Indicate the corresponding column index value.
}

问题出在您对 assert rs.next() 的使用上。 Java中的断言旨在检查不变量(例如在测试期间),但是当您通常不执行运行 Java、assert语句时,它们仅在显式启用时执行这与 -ea 命令行选项。

因此,不会调用 rs.next(),因此当您调用 rs.getInt(1) 时,您的结果集仍位于第一行之前。而是使用 if (rs.next()) { ... }.