我正在使用tomcat连接池运行ORA Cursor超过第三方应用程序的问题。
除了解决这些问题外,我们还想通过设置:
来发布空闲会话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。
答案 0 :(得分:2)
这是一个非常棘手的话题
<强>前言强>
设计连接池,一方面限制与数据库的最大同时打开连接,另一方面重用池中的开放连接。
建立与数据库的物理连接需要时间。通过保持连接打开(在池中)来“保存”这个时间。
<强>连接处理强>
在java 7之前,您必须确保在使用它之后关闭连接。主要是在最后一块:
Connection conn = [retrieve DB-Connection];
try {
// do something
} catch (SQLException e) {
// handle exception
} finally {
conn.close();
}
结合连接池,连接没有物理关闭,在Statement
和ResultSet
关闭后,它刚刚释放到连接池,可以重复使用。
从java 7开始,上面的代码应该/看起来像那样:
try (Connection conn = [retrieve DB-Connection]) {
// do something
} catch (SQLException e) {
// handle exception
}
这是新的“资源试用”功能。只要保留try-block,try的parantheses中的资源就会被关闭(autocloseable)。这些parantheses可以包含严格的,以分号分隔的自动封闭资源。
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或false:是否删除废弃的 从游泳池连接。默认值:false
- removeAbandonedTimeout - The 假定借用连接的秒数 弃。默认值:300
- logAbandoned - true或false:是否记录 应用程序代码的堆栈跟踪放弃了语句或 连接。这增加了严重的开销。默认值:false
游标和“ORA游标超过”-Exception
打开游标的最大值是变量数据库属性。
因此,通过在一个连接中执行大量查询而不关闭“先前”打开/创建的结果集和语句,可能会发生ORA Cursor exceed
异常
以下示例导致五个打开的游标。在这种情况下,使用带有资源的try-catch,并通过离开try-block自动关闭ResultSet
s,Statement
和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之前,如果Statement
和ResultSet
未手动关闭且连接本身未关闭/已释放,则也可能发生错误
以下示例是一个“不良做法”示例,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,并且有一个bad-practice-code-snippet,应用程序可以非常快速地运行到“ORA Cursor exceeded”-Exception
在这种情况下,连接池
放弃功能
照顾你并关闭/释放连接,并隐含Statement
和ResultSet
内的连接。
<强>结论强>
的
放弃功能
只是一个后备。
最好确保ResultSet
,Statement
和Connection
处理和关闭正确。