【问题标题】:PSQLException: this ResultSet is closedPSQLException:此 ResultSet 已关闭
【发布时间】:2018-08-16 14:02:49
【问题描述】:

我有生以来第一次遇到这个奇怪的错误,我不知道这是什么意思。我有一个类可以从 postgresql 数据库的表中检索信息,执行一些操作并返回一个带有解析元素的数组列表:

ResultSet rs = ProduttoreDCS.getProduttori();
        System.out.println("Recuperato result set produttori");
        ArrayList<String[]> res = new ArrayList<String[]>();


        while (rs.next()) {
            String[] current = new String[6];

            current[0] = Integer.toString(rs.getInt("partita_iva"));
            current[1] = rs.getString("nome");
            current[2] = rs.getString("cognome");
            current[3] = rs.getString("via_sede");
            current[4] = rs.getString("citta_sede");
            current[5] = rs.getString("provincia_sede");

            res.add(current);
            current = null;
        }

        return res;

错误出现在“while”行。

public static ResultSet getProduttori() throws ClassNotFoundException, SQLException {
    /*
     * retrieve all record from produttori table
     */
    Connection conn = null;
    ResultSet res = null;
    Statement stmt = null;
    String query = "SELECT * FROM produttore";

    conn = ConnectionManager.getConnection();
    System.out.println("Connection obtained by ProduttoreDCS class");
    stmt = conn.createStatement();
    res = stmt.executeQuery(query);

    stmt.close();
    conn.close();


    return res;   
}

【问题讨论】:

  • 向我们展示 getProduttori() 方法
  • getProduttori 到底是做什么的?如果它试图多次重用相同的 ResultSet 对象,这很容易成为问题。 (顺便说一下,没有理由将current 设置为null。)
  • @jon skeet 我知道,删除它!编辑主帖

标签: java postgresql exception resultset


【解决方案1】:

我通过运行错误的组合遇到了同样的问题:

Postgres 版本; 休眠方言; postgres jdbc 驱动;

全部更新到最新版本解决了我的问题。

附注我知道这不是 OP 所要求的,但这是您在 Google 中搜索问题时的第一个结果。

【讨论】:

  • 它对我有用。确保您的项目中的 postgres jdbc lib 支持 postgres 版本。如果您运行的是 PostgreSQL 9.6,请使用 PostgreSQL JDBC 9。
【解决方案2】:

当您在getProduttori 方法中关闭连接对象时,您的结果集将自动关闭。当您尝试重新使用它时,它将为空。

ResultSet rs = ProduttoreDCS.getProduttori();
             = null, as you have closed the connection in getProduttori
               method, which will automatically close the resultset 
               thus, it returns null.

来自Connection#close

释放此 Connection 对象的数据库和 JDBC 资源 立即而不是等待它们被自动释放。

在关闭语句时也同样适用。为了让您的代码正常工作,在获得行之前不要关闭语句和连接。

@Baadshah 已经向您展示了标准方式。如果您使用的是 java 7+,则可以使用 try-with-resource 块,这将使您的生活更简单。

 try(Connection conn = gettheconn){
     get the statement here
     get the result set 
      perform your ops
 }
 catch(SQLException ex){
   ex.printstacktrace(); 
  }

如果你观察到,没有 finally 块,你的连接对象将在你退出 try 块后自动关闭。你不必显式调用 Connection#close()

【讨论】:

  • 所以我只需要在 getProduttori 方法中移动第一部分代码并将 ArrayList 返回给调用者方法?
  • 是的,这确实是标准的做法
  • 是的,我强迫我的团队升级到 java 7,这样我就可以在使用 JDBC 时跳过所有那些最终阻塞的戏剧。 :P
【解决方案3】:

As per Docs

当生成它的 Statement 对象关闭、重新执行或用于从多个结果序列中检索下一个结果时,ResultSet 对象会自动关闭。

您关闭了连接,然后您正在迭代,它为空。请读取数据然后关闭连接。

这里的一个好习惯是

Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
try {
    conn = 
    stmt = conn.prepareStatement("sql");
    rs = stmt.executeQuery();
   //DO SOME THING HERE
} catch {
    // Error Handling
} finally {
    try { if (rs != null) rs.close(); } catch (Exception e) {};
    try { if (stmt != null) stmt.close(); } catch (Exception e) {};
    try { if (conn != null) conn.close(); } catch (Exception e) {};
}

【讨论】:

  • 我的心 try with resource 来自 java 7 :)
  • @PermGenError 是啊是啊..这是现有代码 :) Haaav ..必须移动 java 7 :P
【解决方案4】:

这就是问题所在:

stmt.close();
conn.close();

您正在关闭与数据库的连接。在您读取数据之前,您不能这样做 - 否则ResultSet 将如何读取它?也许一开始它会读取 一些 数据,但它并不意味着是一个断开连接的对象。

特别是来自ResultSet.close 的文档:

注意:当 Statement 对象关闭、重新执行或用于从多个结果序列中检索下一个结果时,生成它的 Statement 对象会自动关闭 ResultSet 对象。

【讨论】:

    【解决方案5】:

    关闭连接会使结果集消失。

    ResultSet 不是一个可以用来传递数据的容器,它只是一个游标的包装器。您应该遍历 resultSet 内容并将它们复制到数据结构中,然后返回数据结构。你已经这样做了,但你需要在关闭语句和连接之前这样做。

    将代码改为:

    public static List<String[]> getProduttori() throws ClassNotFoundException, SQLException {
    
        ArrayList<String[]> res = new ArrayList<String[]>();
        /*
         * retrieve all record from produttori table
         */
        Connection conn = null;
        ResultSet rs = null;
        Statement stmt = null;
        String query = "SELECT * FROM produttore";
    
        conn = ConnectionManager.getConnection();
        try {
            System.out.println("Connection obtained by ProduttoreDCS class");
            stmt = conn.createStatement();
            try {
                rs = stmt.executeQuery(query);
                while (rs.next()) {
                    String[] current = new String[6];
                    current[0] = Integer.toString(rs.getInt("partita_iva"));
                    current[1] = rs.getString("nome");
                    current[2] = rs.getString("cognome");
                    current[3] = rs.getString("via_sede");
                    current[4] = rs.getString("citta_sede");
                    current[5] = rs.getString("provincia_sede");
                    res.add(current);
                }        
                return res;
            } finally {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    log.error(e);
                }
            }
        } finally {
            try {
            conn.close();
            } catch (SQLException e) {
                log.error(e);
            }
        }        
    }
    

    【讨论】:

    • 这个问题是如果你想将数据库调用抽象到一个单独的类中,使用这种技术会变得很困难,因为你在这里将类的数据与数据库连接方法混合在一起。
    • @John:同意,我更愿意在这里使用 spring 和 spring-jdbc 保持连接获取完全分开。在我看来,这似乎不是问题的一部分。
    猜你喜欢
    • 2018-09-17
    • 2015-04-09
    • 2019-04-05
    • 1970-01-01
    • 2015-04-25
    • 2020-03-31
    • 2018-09-23
    • 2021-01-18
    相关资源
    最近更新 更多