在查询 Oracle 的错误时,是不是有任何避免 Stream 的解决方法已经关闭?

Posted

技术标签:

【中文标题】在查询 Oracle 的错误时,是不是有任何避免 Stream 的解决方法已经关闭?【英文标题】:Any workaround to avoid Stream has already closed when query for Oracle's bug?在查询 Oracle 的错误时,是否有任何避免 Stream 的解决方法已经关闭? 【发布时间】:2021-07-09 04:09:27 【问题描述】:

我使用 ojdbc8 版本 21.1.0.0 作为我的 JDBC。我遇到的问题是每次调用close() 之前我的连接流都会关闭,当我执行我的查询时,由于未知原因从resultSet 请求了很长时间,并且我的SQL 在SQL 开发人员上运行良好。所以我用谷歌搜索并看到这个错误报告在 Oracle 上。

https://support.oracle.com/knowledge/Middleware/832903_1.html

这似乎是他们的 JDBC 的错误?有谁知道哪个版本的 ODBC8 没有这个 bug?或其他解决方法来避免此错误?

==== 更新 ====

@斯蒂芬·C

好吧,如果你这么说。但我认为这无论如何都无济于事,因为代码本身太简单了,不会有这样的错误。

class Channel 
    private static DataSource ds = null;
    private static final String GET_ONE = "SELECT * FROM Channel WHERE Id=?";
    
    public Channel() 
        if(ds == null) 
            try 
                Context ctx = new InitialContext();
                ds = (DataSource) ctx.lookup("jdbc/oracle");
             catch (NamingException e) 
                e.printStackTrace();
            
        
    

    public HashMap<String, Object> getOne(String id) throws SQLException
        HashMap<String, Object> result = null;
        ResultSet rs = null;
        
        try(Connection conn = ds.getConnection();
            PreparedStatement pstmt = con.prepareStatement(GET_ONE);)
            
            pstmt.setString(1, id);
            
            rs = pstmt.executeQuery();
            
            if(rs.next())
                result = new HashMap<String, Object>();
                result.put("Time_Limit", rs.getLong("Time_Limit"));// recommended by @tgdavies
                result.put("Id", rs.getString("Id"));
                result.put("Name", rs.getString("Name"));
            
        
         catch(SQLException e)
            throw e;
         finally 
            if(rs != null)
                try
                    rs.close();
                 catch(SQLException e)
            
        
        
        return result;
    

【问题讨论】:

如果您使用的是非常旧的驱动程序版本,请升级。如果您使用的是最新版本,并且看起来有问题,请提交报告并降级到之前最近的稳定版本。 您是否尝试过在任何其他列之前先从 ResultSet 读取 LONG 值的解决方案?见blog.jooq.org/2015/12/30/… @tgdavies 尝试先读取 Long 值,但仍然出现该错误 @TimBiegeleisen 试图降级到 19.7.0.0,但现在没有运气 真正的原因很可能是>您的minimal reproducible example。 【参考方案1】:

我想我知道问题出在哪里了。

(警告:您没有包含堆栈跟踪,所以我无法确认这一点。此外,您发布的链接未打开,因此我们无法看到您正在谈论的错误报告的详细信息。)

    try(Connection conn = ds.getConnection();
        PreparedStatement pstmt = con.prepareStatement(GET_ONE);)
        
        pstmt.setString(1, id);
        
        rs = pstmt.executeQuery();
        
        if(rs.next())
            result = new HashMap<String, Object>();
            result.put("Time_Limit", rs.getLong("Time_Limit"));// recommended by @tgdavies
            result.put("Id", rs.getString("Id"));
            result.put("Name", rs.getString("Name"));
        
    
     catch(SQLException e)
        throw e;
     finally 
        if(rs != null)
            try
                rs.close();
             catch(SQLException e)
        
    

问题是finally 在资源自动关闭后执行。因此,您的代码将在PreparedStatement 关闭后调用rs.close()。但关闭语句会关闭从该语句创建的任何结果集。

参考:

Are resources closed before or after the finally?

可能的解决方案:

    也将ResultSet 视为资源;例如使用嵌套的尝试使用资源。 摆脱finally ...

【讨论】:

我不明白的东西:我已经忽略了这一行 catch(SQLException e),所以我不认为在执行它时会出现流关闭异常。对吗? 嗯......从堆栈跟踪中应该清楚SQLException 被抛出的位置。它可能发生在 try 块中,这会使我的解释不正确。 (但 minrep 应该包含一个堆栈跟踪...) 如果这确实是一个驱动程序错误,那么您应该与 Oracle 支持人员讨论解决方法和替代版本。 这看起来是正确的答案。删除 finally 块。你不需要它。

以上是关于在查询 Oracle 的错误时,是不是有任何避免 Stream 的解决方法已经关闭?的主要内容,如果未能解决你的问题,请参考以下文章