java - 无法在 Java 中遍历 ResultSet
问题描述
我有个问题。我在我的 java 项目中使用以下 MySQL 驱动程序:
// SET THE MYSQL DRIVER
Class.forName("com.mysql.cj.jdbc.Driver");
SqlConn sqlConn = new SqlConn();
在SqlConn
课堂上,我有以下功能:
public ResultSet executeQuery(String query) {
Statement stmt = null;
ResultSet rs = null;
try {
stmt = conn.createStatement();
if (stmt.execute(query)) {
rs = stmt.getResultSet();
}
// Now do something with the ResultSet ....
} catch (SQLException ex) {
System.out.println("SQLException: " + ex.getMessage());
System.out.println("SQLState: " + ex.getSQLState());
System.out.println("VendorError: " + ex.getErrorCode());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (rs != null) {
try {
rs.close();
} catch (SQLException ignored) {
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException sqlEx) {
} // ignore
stmt = null;
}
}
return rs;
}
该函数的使用如下:
ResultSet result = sqlConn.executeQuery("SELECT Market, Coin FROM Wallets GROUP BY Market, Coin ORDER BY Market, Coin;");
但是当我想像这样循环它时:
while (result.next()) {
System.out.println(result.getString("Market"));
System.out.println(result.getString("Coin"));
System.out.println();
}
我收到以下错误:
Exception in thread "main" java.sql.SQLException: Operation not allowed after ResultSet closed
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:129)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:89)
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:63)
at com.mysql.cj.jdbc.result.ResultSetImpl.checkClosed(ResultSetImpl.java:464)
at com.mysql.cj.jdbc.result.ResultSetImpl.next(ResultSetImpl.java:1744)
at com.company.drivers.SimulatorDriver.main(SimulatorDriver.java:82)
我做错了什么,我该如何解决?
解决方案
在您粘贴的代码中,您首先创建一个连接,然后您无法关闭(资源泄漏!),然后您创建一个语句和一个结果集。在返回之前,您总是(通过 finally 块)关闭这些。因此,此方法创建一个 ResultSet,它立即关闭并返回这个现在关闭的结果集。
所有这些东西都是 20 多年前的想法。尝试用一些不错的方法来覆盖 JDBC 是完全有意义的,但绝对没有必要自己发明这个轮子;使用为您完成此操作的JOOQ或JDBI 。
如果您坚持使用此代码,请对此代码进行一些注释:
在管理资源时使用 try-with-resources,不要使用 finally 块。
所有 3 件事都需要关闭(Connection、Statement 和 ResultSet),但请注意 close() 传播:如果关闭结果集,则只需关闭结果集,但如果关闭语句,还会关闭它产生的任何结果集,并且如果你关闭一个连接,你也会依次关闭它产生的任何语句(以及所有结果集)。这使得编写这样的方法实际上是不可能的(你如何管理如何关闭事物)?因此,研究 lambdas。无论如何,您都希望使用 lambdas 重试。
声明几乎完全没用。当你有参数化查询时(即
SELECT * FROM users WHERE username = ... username the user just entered into a web form here ...
你不能使用任何一个:你不能在连接用户名的地方创建一个字符串,因为如果在表单上输入的用户名是whatever' OR 1 == 1; DROP TABLE users CASCADE; EXEC 'format C: /y';
?不,唯一的方法to goPreparedStatement
支持参数化,不会立即让您面临 SQL 注入攻击。说真的,JOOQ 或 JDBI 做到了这一切,而且做得更好。
你不需要
Class.forName("com.mysql.cj.jdbc.Driver");
——已经 20 年不需要它了。这种“白手起家,出结果集”的模式是行不通的。数据库有交易;有一个更大的上下文(事务),通常包含多个查询。您需要重新设计此 API 以考虑到这一点:或者将连接对象传递给 executeQuery 方法,或者让您自己的对象表示连接,并且它将具有查询方法。JOOQ 和 JDBI 也涵盖了这一点。假设非灾难性危险的隔离级别,即使是一系列只读查询也需要事务。
推荐阅读
- haskell - zip循环列表,哪种方式高效?
- angularjs - 当我输入一个字段时,它会自动输入另一个字段
- sql - 从 SQL Server 2012 中具有几何数据的表中将坐标划分为 X 和 Y 坐标
- html - 如何制作水平滚动的网站?
- java - 如何将文件保存在下载目录中?
- c++ - “Concurrency in Action”原子操作示例的正确性
- ios - 如何将数据添加到地图
- javascript - Firebase 的 WebStorm 代码完成不起作用
- ios - 在特定的 Firebase 结构中过滤
- nlp - tesseract 可以与孟加拉语等语言一起使用吗?如果是这样,我应该以多少准确度和哪些步骤来为孟加拉语实施它?