tomcat 连接池没有关闭连接?
tomcat connection pool does not close connection?
我 运行 使用 ORA Cursor exceed 第三方应用程序使用 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;
这显示了我 "old" session/cursors 和绝对超过 1 分钟的陈述。
我是否缺少其他选项?
感谢和欢呼,E.
这是一个非常棘手的话题
前言
连接池的设计,一方面是为了限制数据库同时打开的最大连接数,另一方面是为了重用池中打开的连接。
建立与数据库的物理连接需要时间。这次是 'saved' 通过保持连接打开(在池中)。
连接处理
before java 7、使用后一定要关闭连接。大部分在 finally 块中:
Connection conn = [retrieve DB-Connection];
try {
// do something
} catch (SQLException e) {
// handle exception
} finally {
conn.close();
}
结合连接池,连接在物理上并没有关闭,只是释放到连接池中,在Statement
s和ResultSet
s关闭后,可以重复使用。
因为 java 7,上面的代码 should/can 看起来像这样:
try (Connection conn = [retrieve DB-Connection]) {
// do something
} catch (SQLException e) {
// handle exception
}
这是新的 "try-catch with resources" 功能。无论何时离开 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
}
如果连接不是 closed/released 手动或由 "try-catch with resources" 处理,连接池有一个可配置的后备功能 -
the abandoning feature
处理 unclosed/unreleased (已放弃)连接。
请参阅 tomcat-版本相关的 "JNDI-Resources how to" -> "JDBC Data Sources" 文档。此 link 与版本 9.0
相关
The abandoning feature is disabled by default and can be configured using
the following properties:
- removeAbandoned - true or false: whether to remove abandoned
connections from the pool. Default: false
- removeAbandonedTimeout - The
number of seconds after which a borrowed connection is assumed to be
abandoned. Default: 300
- logAbandoned - true or false: whether to log
stack traces for application code which abandoned a statement or
connection. This adds serious overhead. Default: false
游标和 "ORA Cursor exceed"-Exception
最大打开游标为可变数据库-属性.
因此,通过在一个连接中执行大量查询而不关闭 'previous' opened/created 结果集和语句,可能会发生 ORA Cursor exceed
异常
以下示例导致打开五个游标。在这种情况下,使用带有资源的 try-catch,并且 ResultSet
s、Statement
s 和 Connection
通过离开 try-block:
自动关闭
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
}
before java 7,如果Statement
s和ResultSet
s没有手动关闭并且连接本身不是closed/released[=37=,也可能会出现错误]
下面的例子是'bad practice'的例子,ResultSet
和Statement
和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,并且有一个错误做法代码片段,应用程序可能 运行 很快进入 "ORA Cursor exceed"-Exception
在这种情况下,连接池
abandoning feature
照顾你和 closes/releases 的联系,并暗中 Statement
和 ResultSet
之间的联系。
结论
abandoning feature
只是后备。
最好确保 ResultSet
、Statement
和 Connection
得到正确处理和关闭。
我 运行 使用 ORA Cursor exceed 第三方应用程序使用 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;
这显示了我 "old" session/cursors 和绝对超过 1 分钟的陈述。
我是否缺少其他选项? 感谢和欢呼,E.
这是一个非常棘手的话题
前言
连接池的设计,一方面是为了限制数据库同时打开的最大连接数,另一方面是为了重用池中打开的连接。
建立与数据库的物理连接需要时间。这次是 'saved' 通过保持连接打开(在池中)。
连接处理
before java 7、使用后一定要关闭连接。大部分在 finally 块中:
Connection conn = [retrieve DB-Connection];
try {
// do something
} catch (SQLException e) {
// handle exception
} finally {
conn.close();
}
结合连接池,连接在物理上并没有关闭,只是释放到连接池中,在Statement
s和ResultSet
s关闭后,可以重复使用。
因为 java 7,上面的代码 should/can 看起来像这样:
try (Connection conn = [retrieve DB-Connection]) {
// do something
} catch (SQLException e) {
// handle exception
}
这是新的 "try-catch with resources" 功能。无论何时离开 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
}
如果连接不是 closed/released 手动或由 "try-catch with resources" 处理,连接池有一个可配置的后备功能 -
the abandoning feature处理 unclosed/unreleased (已放弃)连接。
请参阅 tomcat-版本相关的 "JNDI-Resources how to" -> "JDBC Data Sources" 文档。此 link 与版本 9.0
相关The abandoning feature is disabled by default and can be configured using the following properties:
- removeAbandoned - true or false: whether to remove abandoned connections from the pool. Default: false
- removeAbandonedTimeout - The number of seconds after which a borrowed connection is assumed to be abandoned. Default: 300
- logAbandoned - true or false: whether to log stack traces for application code which abandoned a statement or connection. This adds serious overhead. Default: false
游标和 "ORA Cursor exceed"-Exception
最大打开游标为可变数据库-属性.
因此,通过在一个连接中执行大量查询而不关闭 'previous' opened/created 结果集和语句,可能会发生 ORA Cursor exceed
异常
以下示例导致打开五个游标。在这种情况下,使用带有资源的 try-catch,并且 ResultSet
s、Statement
s 和 Connection
通过离开 try-block:
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
}
before java 7,如果Statement
s和ResultSet
s没有手动关闭并且连接本身不是closed/released[=37=,也可能会出现错误]
下面的例子是'bad practice'的例子,ResultSet
和Statement
和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,并且有一个错误做法代码片段,应用程序可能 运行 很快进入 "ORA Cursor exceed"-Exception
在这种情况下,连接池
abandoning feature
照顾你和 closes/releases 的联系,并暗中 Statement
和 ResultSet
之间的联系。
结论
abandoning feature
只是后备。
最好确保 ResultSet
、Statement
和 Connection
得到正确处理和关闭。