java - 无法在 Java 中循环 ResultSet

标签 java mysql sql 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 block )关闭这些。因此,此方法创建一个 ResultSet,它立即关闭并返回这个现在关闭的结果集。

所有这些东西都是 20 多年前的想法。尝试用一些好的方法来掩盖 JDBC 是完全有意义的,但绝对没有必要自己发明这个轮子;使用JOOQJDBI它为你做了这件事。

如果您坚持使用此代码,请注意此代码:

  1. 在管理资源时使用 try-with-resources,不要使用 finally block 。

  2. 所有 3 件事都需要关闭(Connection、Statement 和 ResultSet),但请注意 close() 会传播:如果关闭结果集,则只是关闭结果集,但如果关闭语句,则也会关闭它生成的任何结果集,如果关闭连接,您也会依次关闭它生成的任何语句(以及所有结果集)。这使得编写这样的方法实际上是不可能的(你如何管理如何关闭事物)?因此,研究 lambda。无论如何,您都需要 lambda 来重试。

  3. 声明几乎完全没有用。当您进行参数化查询时(即 SELECT * FROM users WHERE username = ...用户名刚刚在此处输入到网络表单中的用户名...,您不能使用以下任何一个:您可以'不要在连接用户名的地方创建一个字符串,因为如果在表单上输入的用户名是 whatever' OR 1 == 1; DROP TABLE users CASCADE; EXEC 'format C:/y';?不,唯一的方法是 PreparedStatement,它支持参数化,但不会立即让您遭受 SQL 注入(inject)攻击。

  4. 说真的,JOOQ 或 JDBI 做到了这一切,而且做得更好。

  5. 您不需要 Class.forName("com.mysql.cj.jdbc.Driver"); - 20 年来都不需要它。

  6. 这种“从无到有,结果集”的模型行不通。 DB 有事务;有一个更大的上下文(事务),通常包含多个查询。您需要重新设计此 API 以考虑到这一点:要么将连接对象传递给executeQuery 方法,要么创建您自己的对象来表示连接,并且它将具有查询方法。 JOOQ 和 JDBI 也涵盖了这一点。假设非灾难性危险的隔离级别,即使是一系列只读查询也需要事务。

关于java - 无法在 Java 中循环 ResultSet,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66561983/

相关文章:

java - 如何使用hibernate模板从数据库中获取数据

java - 我需要为立即触发设置什么样的失火指令?

java - java中的Mongo聚合: group with multiple fields

c++ - mysql connector c++ 安装在树莓派上

sql - 提高 Ruby 脚本处理 CSV 的性能

JAVA:如何加密和查看图像

mysql - GROUP_CONCAT 一条选择语句

mysql - 如何将用户连接到mysql数据库?

java - 为什么会出现 "MySQLSyntaxErrorException:"错误?

c# - 使用 LINQ 对 ID、EmailListID、PhoneListID 等进行分组