使用simplejdbccall时如何在spring中关闭refcursor

Posted

技术标签:

【中文标题】使用simplejdbccall时如何在spring中关闭refcursor【英文标题】:How to close refcursor in spring when using simplejdbccall 【发布时间】:2014-05-27 16:56:51 【问题描述】:

我正在使用 spring simpleJdbcCall 来调用 oracle 存储过程,并且我正在使用 oracle 11g。

我偶然发现了几篇帖子,这些帖子表明可能存在内存泄漏,因为引用游标没有被 spring 正确关闭。

在使用 spring simplejdbccall 时是否有显式关闭游标?还是增加oracle OPEN_CURSOR 是唯一的出路?

我计划扩大我的应用程序,使其每小时处理大约一百万笔交易。任何建议都会有所帮助。

【问题讨论】:

【参考方案1】:

其实Spring JDBC不存在这样的问题。它在所有执行后关闭finally 内的所有资源。 SimpleJdbcCall 使用JdbcTemplate

public <T> T execute(CallableStatementCreator csc, CallableStatementCallback<T> action)
            throws DataAccessException 
     try 
         ...
     
     catch (SQLException ex) 
         ...
     
     finally 
        if (csc instanceof ParameterDisposer) 
          ((ParameterDisposer) csc).cleanupParameters();
        
        JdbcUtils.closeStatement(cs);
        DataSourceUtils.releaseConnection(con, getDataSource());
     


ResultSetOUT 参数也一样:

protected Map<String, Object> processResultSet(ResultSet rs, ResultSetSupportingSqlParameter param) throws SQLException 
   ....
   finally 
       JdbcUtils.closeResultSet(rs);
   
   return returnedResults;

另一方面,我在高负载系统中使用 Spring JDBC 和 Oracle 有丰富的经验,我想说的是,我们注意到 Oracle 上有足够的开放资源在峰值负载下,但在那之后它们已被正确释放。

虽然我们使用了 JBOSS Pooled DataSource 及其 TransactionMaanger

【讨论】:

谢谢Artem。这很有帮助!!【参考方案2】:

我直接使用CallableStatement,我可以快速安全地释放语句和连接,尝试两种方法并测量内存消耗,它完美地解决了内存消耗和连接保留问题,证明了应用程序的许多等待和拒绝连接。

try 
        log.info("**** RepositoryPSostgres.getAllProducts ******** ");
        Connection conn = jdbcTemplate.getDataSource().getConnection();
        conn.setAutoCommit(false);
        // Procedure call.
        CallableStatement proc = conn.prepareCall("? = call get_all_products() ");
        proc.registerOutParameter(1, Types.OTHER);
        proc.execute();
        ResultSet results = (ResultSet) proc.getObject(1);
        **proc.close();
        proc.isClosed();
        conn.close();**
        ArrayList <Products> resp = new ArrayList <Products>();

        while (results.next()) 
            Products resp1 = new Products();
            resp1.setId(results.getInt("id"));
            resp1.setName((String) results.getString("name"));
            resp1.setPrice((BigDecimal) results.getBigDecimal("price"));
            resp.add(resp1);
            log.info("***" + results.getInt("id") + "***** ");
            log.info("***" + results.getString("name") + "***** ");
            log.info("***" + results.getBigDecimal("price") + "***** ");
        
    results.close();
    return resp;
     catch (Exception e) 
        e.printStackTrace();
        log.error(new StringBuffer("Error en transaccion en saldo CashPooling : ").append(e.getLocalizedMessage()).toString());
        return null;
    

【讨论】:

以上是关于使用simplejdbccall时如何在spring中关闭refcursor的主要内容,如果未能解决你的问题,请参考以下文章

如何在 spring 中使用 SimpleJDBCCall 获取存储过程的结果以及两个结果表?

从spring boot simpleJDBCcall调用PL SQL过程时出错

SimpleJdbcCall - 执行 oracle 程序时出错

避免多次创建 SimpleJdbcCall

带有 JdbcTemplate 自动装配的 SimpleJdbcCall 的 Junit

将 simplejdbccall 结果集转换为 java 对象