Java 将结果集返回给另一个函数

Java 将结果集返回给另一个函数,java,jdbc,javabeans,resultset,Java,Jdbc,Javabeans,Resultset,我正在创建一个程序来管理MySQL服务器。我有一个可以正常工作的UI和代码,可以向数据库添加新条目。下图是我正在使用的原型GUI,对这个问题很重要的部分是表框,它将在数据库工作时显示数据库的条目 我拥有的用于读取数据库内容的代码可以正常工作。该程序是结构化的,因此我有单独的类用于接口、场景控制器和SQL命令。我要处理的问题是,我可以从数据库中提取所需的数据,但是让场景控制器类将其写入数据库根本不起作用 相关代码如下所示 SQL函数: public ResultSet readDataBase(

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

我拥有的用于读取数据库内容的代码可以正常工作。该程序是结构化的,因此我有单独的类用于接口、场景控制器和SQL命令。我要处理的问题是,我可以从数据库中提取所需的数据,但是让场景控制器类将其写入数据库根本不起作用

相关代码如下所示

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();
    }
}
场景控制器块中代码的目的只是暂时测试和读取结果集。稍后将添加用于将结果中的数据写入各自表的写入代码。之所以选择这段代码,是因为我最初将它放在SQL functions类中,并且它在那里工作,所以我知道这段代码很好,并且完成了它的工作

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

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)
我之前读过一些,但我能找到的唯一真正相关的信息来源是七年前的这篇文章。这个问题的答案提到了使用JavaBeans作为放置信息的中间位置,但随后在示例代码中使用了一个名为“Biler”的类。除了他的帖子和我的IDE(IntelliJ,如果相关的话)根本不认识它之外,我在任何地方都找不到任何关于比尔的引用。我一直在用JavaBeans做一些实验,但我不确定它是否解决了我的问题


总之,我的问题是。为了将ResultSet从访问SQL server的函数正确地传递给包含将其写入接口中表的代码的类,我需要做什么?我知道这一定是可能的,但我似乎无法理解。

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

try {

    return resultSet;

} finally {
    close();
}

我认为无论如何,传回结果集是一种不好的做法,因为结果集不是真正的类型安全的。如果更改查询,您将在不注意的情况下中断fillTable()函数。当然,您需要找到一种方法在某个时候关闭resultset和底层DB连接。这可能很有挑战性。

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

您需要将数据从结果集中复制出来,或者使用实用程序来执行此操作

CachedRowSet
A也许是解决办法。这个接口扩展了。有关解释,请参阅Oracle提供的

您可以使用将结果集数据的副本保存在内存中的接口,并与数据库分离。Oracle提供了一个实现,其他供应商如您的

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

CachedRowSet对象是数据行的容器,它将数据行缓存在内存中,这样就可以在不总是连接到数据源的情况下进行操作。此外,它是一个JavaBeans™ 组件,并且是可滚动、可更新和可序列化的

该接口由多个接口扩展

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

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

记录 当使用Java16中的新记录功能时,为这样的POJO定义一个类要简单得多,现在已经预览过了。构造函数、getter、
toString
equals
&
hashCode
都是由编译器合成的。您只需声明属性


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

这似乎很有希望!我的印象是,通过使用ResultSet,我将访问代码与接口代码分开。我的错误是没有完全理解结果集是如何工作的。我认为它类似于任何标准变量,比如Int、String或Array,它更持久,不依赖于仍然处于活动状态的连接。缓存行集似乎非常适合我的问题,我一回到计算机就会对其进行测试。好吧,所以让cachedRowSet正常工作所花费的时间比我想象的要长得多(URL根本不起作用,我真的不知道为什么),但我终于让它起作用了。cachedRowSet做了我需要的一切!非常感谢你的帮助!我建议不要使用
CachedRowSet
,而是填充POJO列表。Java附带的
javax.sql.RowSet
参考实现有很多缺陷(或者至少,每次我接触它时,都会遇到错误行为和对JDBC需求的错误解释的问题)。@MarkrotVeel在提出这样的批评时,我建议链接到困扰您的特定实现。有特定问题的特定实现不会使行集的概念失效。我提到了具体的实现:Java中包含的参考实现,这是大多数人将要使用的。这是我艰难发现的。我真的低估了结果集的工作原理,只是简单地假设它们