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()) { ... }
.
你好,感谢阅读。 我正在尝试检索新插入数据的 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()) { ... }
.