作为初级Java开发人员,我们在职业生涯的早期就了解JDBC API。 我们知道它是非常重要的抽象,因为它允许以透明的方式更改基础数据库。 恐怕一个好主意是过度工程,因为:
- 我从未见过这样的数据库迁移发生超过十年了
- 大多数时候,写的SQL 不是独立于数据库
尽管如此,无可否认,JDBC是Java中每个数据库交互的基础。 但是,我最近偶然发现了一个非常深藏在javax.sql.Connection
接口核心的陷阱。 基本上,您可能已经被告知关闭Connection
返回的Statement
? 还要关闭Statement
返回的ResultSet
吗? 但是也许您还被告知关闭Connection
将关闭所有基础对象Statement
和ResultSet
?
那么,哪个是对的? 好吧,``取决于情况'',还有麻烦......
- 一方面,如果从
DriverManager
返回连接,则调用Connection.close()
将关闭与数据库和所有基础对象的物理连接。 - 另一方面,如果连接是从
DataSource
返回的,则调用Connection.close()
只会将其返回到池中,您需要自己关闭语句。
在后一种情况下,如果不关闭这些基础语句,则数据库游标将保持打开状态,在某个时候将达到RDBMS限制,并且将不执行新的语句。 结论: 总是关闭语句对象 (就像我已经写过的一样 )! 请注意,语句结束后,结果集将关闭。
如果您幸运地使用Java 7-并且不使用数据访问框架,则使用的代码如下:
try(PreparedStatementps=connection.prepareStatement("Put SQL here")){
try(ResultSetrs=ps.executeQuery()){
// Do something with ResultSet
}
}catch(SQLExceptione){
// Handle exception
e.printStackTrace();
}
并且,如果您想确保即使错误代码也将关闭游标,那么老式的Tomcat为此提供了StatementFinalizer
拦截器 。 声明Resource
时,只需在server.xml
配置文件中对其进行配置:
<Resourcename="jdbc/myDB"auth="Container"type="javax.sql.DataSource"
jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"/>
在那里,您还可以检查ResetAbandonedTimer拦截器。 它可以与removeAbandonedTimeout属性结合使用:这配置了将连接返回到池之前的时间。 如果属性的值太低,则可能会返回使用中的连接。 使用拦截器,每次使用连接都会重置计时器。