PSQLException:此 ResultSet 已关闭

Posted

技术标签:

【中文标题】PSQLException:此 ResultSet 已关闭【英文标题】:PSQLException: this ResultSet is closed 【发布时间】: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 我知道,删除它!编辑主帖 【参考方案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 保持连接获取完全分开。在我看来,这似乎不是问题的一部分。

以上是关于PSQLException:此 ResultSet 已关闭的主要内容,如果未能解决你的问题,请参考以下文章

PSQLException:在此 ResultSet 中找不到列名 start_value

org.postgresql.util.PSQLException:这个 ResultSet 已经被关闭。

org.postgresql.util.PSQLException:这个 ResultSet 已经被关闭。

PSQLException:此连接已关闭 - Spring Boot + AWS RDS + Postgres

PSQLException:错误:关系“表”不存在

运行测试时Spring Boot“PSQLException:FATAL:抱歉,客户端已经太多”