getGeneratedKeys返回一个空的ResultSet

问题描述

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

 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在评论中提到的那样,问题出在“断言”声明上。

解决方法

问题是您使用了assert rs.next()。 Java中的断言旨在检查不变性(例如,在测试期间),但是当您正常运行Java时,assert语句不会执行,只有在使用-ea命令行选项显式启用此语句时,才会执行它们。 / p>

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

,

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

JDBC是低级的,不适合用于编程

这是一个复杂的API。使用更轻松的方法:JDBI或JOOQ。他们可能对插入有一些抽象,可以为您解决这些问题。

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

尝试:

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

某些数据库引擎只会将生成的值作为直接结果集返回

请勿致电.executeUpdate();而是调用.executeQuery()返回一个ResultSet;检查那个。

还有其他事情

如果上述方法无济于事,请发布您正在使用的确切表结构和数据库引擎。

您的代码已损坏

除非您安全地这样做并且不能安全地这样做,否则您不能创建资源对象(一旦必须被关闭)。使用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));
    }
}

ResultSet,Statement,PreparedStatement和Connections都是资源(必须关闭!)-如果要将这些内容之一存储在字段中,则可以这样做,但前提是包含该字段的类本身是资源:必须具有close()方法,必须实现AutoClosable,然后您才能使用上述try-with-resources制作此类的实例。

不遵守这些规则意味着您的应用程序似乎可以运行,但是在运行时会泄漏资源,因此,如果让它运行足够长时间,它将开始崩溃。另外,随着越来越多的连接一直处于打开状态并永久卡住,您的数据库引擎将陷入停顿。

,

将最后一行代码更改为此,因为您使用的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.
}