You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用JasperReport后连接池连接未释放问题排查与解决求助

问题分析与解决方案

从你的代码和现象来看,核心问题是数据库连接泄漏——每次生成报表时都会多占用一个连接且未正确释放,直到连接池被耗尽,导致超时或阻塞。我们来一步步拆解原因和修复方案:

直接原因:重复获取连接且未关闭

看你生成报表的核心代码片段:

connection = dataSource.getConnection();
final JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, null, dataSource.getConnection());

这里你犯了一个关键错误:

  • 你先获取了一个connection变量,但在fillReport时又调用了dataSource.getConnection(),这会从连接池新获取一个独立连接
  • 你在finally块里只关闭了之前的connection变量,但fillReport使用的那个新连接完全没有被关闭!
  • 每次生成报表就会泄漏一个连接,当泄漏的连接数达到连接池最大容量(Hikari默认10,DBCP默认8)时,就会出现超时或阻塞

而SimpleDriverDataSource是无池化的数据源,每次getConnection()都会创建一个全新的物理连接,用完后JVM最终会自动回收(虽然不优雅),所以不会出现池耗尽的情况,但这显然不适合生产环境。

修复方案:复用已获取的连接并确保关闭

修改代码,让fillReport复用你已经获取的connection,并确保这个连接在finally块被正确关闭:

private void generatePdfReport(final Report report) throws SQLException, JRException {
    final JasperReport jasperReport = JASPER_REPORT_MAP.get(report);
    if (jasperReport == null) {
        throw new UnsupportedOperationException("The report is not supported: " + report.getName());
    } 
    Connection connection = null;
    try {
        connection = dataSource.getConnection();
        // 这里复用已获取的connection,而非重新调用dataSource.getConnection()
        final JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, null, connection);
        final JRPdfExporter exporter = new JRPdfExporter();
        exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
        exporter.setExporterOutput(new SimpleOutputStreamExporterOutput(report.getFormattedFilename() + Report.EXT_PDF));
        exporter.setConfiguration(reportConfig);
        exporter.setConfiguration(exportConfig);
        exporter.exportReport();
        log.info("PDF Report ({}) exported successfully!", report.getName());
    } finally {
        if (connection != null) {
            log.info("about to close db connection");
            try {
                connection.close();
            } catch (SQLException e) {
                log.error("Failed to close database connection", e);
            }
            connection = null;
        }
    }
}

额外排查与优化点

  1. JasperReports连接自动关闭配置
    可以在报表参数中添加net.sf.jasperreports.jdbc.close.connection参数并设置为true,让JasperReports在填充完报表后自动关闭传入的连接(不过更推荐自己显式管理连接,避免依赖框架行为):

    Map<String, Object> params = new HashMap<>();
    params.put("net.sf.jasperreports.jdbc.close.connection", true);
    final JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, connection);
    
  2. TransactionAwareDataSourceProxy的影响
    如果使用TransactionAwareDataSourceProxy,它会把连接绑定到当前事务上下文。如果你的报表生成代码在事务中执行,连接可能不会立即关闭,直到事务提交/回滚。确保报表生成逻辑不在不必要的事务中运行,或者显式控制事务边界。

  3. 版本兼容性检查
    某些旧版本的JasperReports可能存在连接泄漏的bug,建议升级到最新稳定版(比如6.x系列),同时确保JDBC驱动与数据库版本完全兼容。

  4. 连接池监控
    启用连接池的监控功能(HikariCP可以通过HikariMXBean查看连接状态),确认修复后连接是否被正确回收,没有IN_USE的连接堆积。

内容的提问来源于stack exchange,提问作者Julian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:42:26