这是一个非常棘手的话题
前言
连接池的设计目的是一方面限制与数据库的最大同时打开连接数,另一方面重用池中的打开连接数。
建立与数据库的物理连接需要时间。通过保持连接打开(在池中)来“保存”这个时间。
连接处理
在 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 得到正确处理和关闭。