【问题标题】:tomcat connection pool does not close connection?tomcat连接池不关闭连接?
【发布时间】:2018-04-18 08:07:57
【问题描述】:

我遇到了 ORA 游标超出使用 tomcat 连接池的第三方应用程序的问题。

除了解决这些问题,我们还想通过设置来释放空闲会话:

minEvictableIdleTimeMillis =  60000
timeBetweenEvictionRunsMillis = 60000

但不知何故,这些会话似乎根本没有释放(即使没有任何流量):

select  a.value, s.username, s.sid, s.serial#, s.machine, to_char(cast(s.logon_time as date),'hh24:mi:ss') as activesince from v$sesstat a, v$statname b, v$session s where a.statistic# = b.statistic#  and s.sid=a.sid and b.name = 'opened cursors current' and s.username = 'username' order by value desc;

这向我展示了绝对超过 1 分钟的“旧”会话/游标和语句。

我是否缺少其他选择? 谢谢和欢呼,E。

【问题讨论】:

    标签: tomcat connection pool


    【解决方案1】:

    这是一个非常棘手的话题

    前言

    连接池的设计目的是一方面限制与数据库的最大同时打开连接数,另一方面重用池中的打开连接数。

    建立与数据库的物理连接需要时间。通过保持连接打开(在池中)来“保存”这个时间。

    连接处理

    在 java 7 之前,您必须确保在使用后关闭连接。主要在 finally 块中:

    Connection conn = [retrieve DB-Connection];
    try {
        // do something
    } catch (SQLException e) {
        // handle exception
    } finally {
        conn.close();
    }
    

    结合连接池,连接并没有物理关闭,它只是释放到连接池,在Statements和ResultSets关闭后,可以重用。

    从 java 7 开始,上面的代码应该/可以看起来像这样:

    try (Connection conn = [retrieve DB-Connection]) {
        // do something
    } catch (SQLException e) {
        // handle exception
    }
    

    这是新的“资源尝试捕获”功能。无论何时离开 try 块,try 括号内的资源都会关闭(可自动关闭)。括号可以包含重要的、分号分隔的自动关闭资源。

    try (Connection conn = [retrieve DB-Connection];
         Statement stat = conn.createStatement();
         ResultSet result = stat.executeQuery("SELECT 1 FROM DUAL")) {
        // do something
    } catch (SQLException e) {
        // handle exception
    }
    

    如果连接没有手动关闭/释放或由“try-catch with resources”处理,则连接池具有可配置的回退功能 -

    放弃功能
    处理未关闭/未释放(放弃)的连接。

    请参考你的"JNDI-Resources how to" -> "JDBC Data Sources"的tomcat版本相关文档。此链接涉及 9.0 版

    放弃功能默认是禁用的,可以使用配置 以下属性:

    • removeAbandoned - true or false: 是否移除放弃 来自池的连接。默认值:假
    • removeAbandonedTimeout - 的 假定借用连接的秒数 弃。默认值:300
    • logAbandoned - true or false: 是否记录 放弃语句的应用程序代码的堆栈跟踪或 联系。这增加了严重的开销。默认值:假

    游标和“ORA 游标超出”-异常

    打开游标的最大值是一个可变的数据库属性。

    因此,通过在单个连接中执行大量查询而不关闭“先前”打开/创建的结果集和语句,可能会发生 ORA Cursor exceed 异常

    以下示例导致五个打开的游标。在这种情况下,使用资源的 try-catch 并通过离开 try-block 自动关闭 ResultSets、Statements 和 Connection

    try (Connection conn = [retrieve DB-Connection];
         Statement stat0 = conn.createStatement();
         ResultSet result0 = stat0.executeQuery(...);
         Statement stat1 = conn.createStatement();
         ResultSet result1 = stat1.executeQuery(...);
         Statement stat2 = conn.createStatement();
         ResultSet result2 = stat2.executeQuery(...);
         Statement stat3 = conn.createStatement();
         ResultSet result3 = stat3.executeQuery(...);
         Statement stat4 = conn.createStatement();
         ResultSet result4 = stat4.executeQuery(...);) {
        // do something
    } catch (SQLException e) {
        // handle exception
    }
    

    最好将它们分开:

    try (Connection conn = [retrieve DB-Connection]) {
        try (Statement stat0 = conn.createStatement();
             ResultSet result0 = stat0.executeQuery(...)) {
            // do something
        }
        try (Statement stat1 = conn.createStatement();
             ResultSet result1 = stat1.executeQuery(...)) {
            // do something
        }
        try (Statement stat2 = conn.createStatement();
             ResultSet result2 = stat2.executeQuery(...)) {
            // do something
        }
        try (Statement stat3 = conn.createStatement();
             ResultSet result3 = stat3.executeQuery(...)) {
            // do something
        }
        try (Statement stat4 = conn.createStatement();
             ResultSet result4 = stat4.executeQuery(...);) {
            // do something
        }
    } catch (SQLException e) {
        // handle exception
    }
    

    在 java 7 之前,如果 Statements 和 ResultSets 没有手动关闭并且连接本身没有关闭/释放,也可能出现错误

    以下示例是“不良做法”示例,ResultSets 和 Statements 和 Connection 均未关闭

    Connection conn = [retrieve DB-Connection];
    try {
        Statement stat0 = conn.createStatement();
        ResultSet result0 = stat0.executeQuery(...);
        Statement stat1 = conn.createStatement();
        ResultSet result1 = stat1.executeQuery(...);
        Statement stat2 = conn.createStatement();
        ResultSet result2 = stat2.executeQuery(...);
        Statement stat3 = conn.createStatement();
        ResultSet result3 = stat3.executeQuery(...);
        Statement stat4 = conn.createStatement();
        ResultSet result4 = stat4.executeQuery(...);
    } catch (SQLException e) {
        // handle exception
    } 
    

    假设打开游标的最大值为 20,并且有一个 bad-practice-code-sn-p,应用程序可能运行得非常快,进入“ORA 游标超出”-异常

    在这种情况下,连接池

    放弃功能

    照顾您并关闭/释放连接,并隐含其中的Statements 和ResultSets。

    结论

    放弃功能

    只是一个后备。

    最好确保ResultSets、Statements 和Connections 得到正确处理和关闭。

    【讨论】:

    • 谢谢!非常有助于理解和获取一些背景信息!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    相关资源
    最近更新 更多