在查询 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 的解决方法已经关闭?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Data Studio 查询 BigQuery 时如何避免错误?

oracle在没有闪回的情况下怎样找回以删了的表

在ORACLE触发器中想使用into 语句给一个变量赋值,但是查询出来的值可能为空,如何避免报错未找到任何数据

ORA-00936 在 oracle 选择语句中使用日期函数时

查询Spark同时加载的hive表时如何避免错误

在 Oracle 中执行 DELETE 查询时如何重现异常