将 ResultSet 返回给另一个函数

Returning a ResultSet to another function

我正在创建一个程序来管理 MySQL 服务器。我有一个可以正常工作的 UI 和可以向数据库添加新条目的代码。下图是我正在使用的原型 GUI,对问题很重要的部分是 table 框,它将在数据库工作时显示其条目。

我拥有的用于读取数据库内容的代码可以正常工作。该程序的结构使得我有单独的 class 用于界面、场景控制器和 SQL 命令。我正在处理的问题是,我可以从数据库中提取所需的数据,但是让场景控制器 class 将其写入数据库根本行不通。

下面包含相关代码片段。

SQL 函数:

public ResultSet readDataBase() throws Exception{
    try {
        // Establish connection to server
        Class.forName("com.mysql.cj.jdbc.Driver");
        connect=DriverManager.getConnection("jdbc:mysql://localhost/library?"+"user=tempUser&password=12345");
        statement=connect.createStatement();

        // Execute query and write the results
        resultSet=statement.executeQuery("select * from library.books");
        return resultSet;

        // writeResultSet(resultSet);

    } catch (Exception e){
        throw e;
    } finally {
        close();
    }
}

场景控制器代码:

public void fillTable() throws SQLException{
    ResultSet resultSet=null;
    try {
        resultSet=commands.readDataBase();

        while(resultSet.next()) {
            String title = resultSet.getString("title");
            String author = resultSet.getString("author");
            String genre = resultSet.getString("genre");
            String format = resultSet.getString("format");
            String isbn = resultSet.getString("isbn");

            System.out.println("Title: " + title);
            System.out.println("Author: " + author);
            System.out.println("Genre: " + genre);
            System.out.println("Format: " + format);
            System.out.println("ISBN: " + isbn);
            System.out.println();
        }
    }catch (Exception e){
        e.printStackTrace();
    }
}

场景控制器块中代码的目的只是暂时测试和读取结果集。将结果中的数据写入各自的table的writing代码后面会补上。选择此代码是因为我最初将它放在 SQL 函数 class 中并且它在那里工作,所以我知道代码很好并且完成了它的工作。

然而,每当我 运行 代码时,我都会得到这个错误结果。

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:445)
at com.mysql.cj.jdbc.result.ResultSetImpl.next(ResultSetImpl.java:1726)
at library.test.windows.interfaceSceneController.fillTable(interfaceSceneController.java:108)
at library.test.windows.winInterface.main(winInterface.java:33)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)

我之前对此进行了一些阅读,但我能找到的唯一真正相关的信息来源是七年前的 post。该问题的答案提到使用 JavaBeans 作为将信息作为 in-between 放置的地方,但随后在其示例代码中使用了称为 'Biler' 的 class。除了他的 post 和我的 IDE (IntelliJ,如果相关的话)我根本无法识别它,我在任何地方都找不到任何对 Biler 的引用。我一直在用 JavaBeans 做一些实验,但我不确定它能解决我的问题。

综上所述,我的问题是这样的。我需要做什么才能正确地将 ResultSet 从访问 SQL 服务器的函数传递到 class,其中包含用于将其写入我界面中的 table 的代码?我知道这一定是可能的,但我似乎无法弄清楚。

好吧,我假设您要在 close() 方法中关闭连接。所以这就是它关闭的原因。 finally 在方法体之后但在结果传递给调用函数之前执行。

try {

    return resultSet;

} finally {
    close();
}

恕我直言,无论如何传回结果集都是不好的做法,因为结果集并不是真正的类型安全。如果您更改查询,您将在不注意的情况下破坏 fillTable() 函数。而且,当然,您需要找到一种方法在 some 点关闭结果集和基础数据库连接。这可能具有挑战性。

您的数据库访问代码应与您的用户界面代码完全分开。 UI 不应处理活动的 ResultSet.

您需要从结果集中复制数据,或使用实用程序来完成。

CachedRowSet

Oracle 的 RowSet may be the solution. This interface extends ResultSet. See the Java Tutorials 解释。

您可以使用 CachedRowSet interface that keeps a copy of the result set data in memory, detached from the database. Oracle provides an implementation, as might other vendors such as your JDBC driver.

CachedRowSet 实现与数据库断开连接。相反, ResultSet 维护数据库连接(问题的根源)。引用 Java 文档:

A CachedRowSet object is a container for rows of data that caches its rows in memory, which makes it possible to operate without always being connected to its data source. Further, it is a JavaBeans™ component and is scrollable, updatable, and serializable.

该接口又扩展了几个接口。

POJO

普通旧 Java 对象是另一种选择,将 ResultSet 中每一行的每个字段复制到 Java 对象的属性中。

您可以在实例化记录时简单地循环结果集。或者您可以使用各种框架中的任何一种来提供帮助。

记录

使用新 records 功能时,为此类 POJO 定义 class 会简单得多 Java 16,现已预览 in Java 15 .构造器、getters、toStringequals & hashCode都是编译器合成的。您只需声明属性。

记录可以声明为独立的 class,也可以声明为嵌套的 class,甚至可以在方法中本地声明。