【发布时间】:2017-02-15 08:17:31
【问题描述】:
我的连接池一直遇到(我认为)问题。 具体来说,我的日志显示了以下消息:
org.apache.tomcat.dbcp.pool2.impl.DefaultPooledObject$AbandonedObjectCreatedException: 以下代码创建的池化对象 [时间] 尚未返回到池中
我检查了日志显示的堆栈跟踪中列出的方法,但找不到罪魁祸首(我总是在每个方法的末尾关闭 ResultSet、PreparedStatement 和 Connection)。
我有一个执行两个查询的方法,也许我没有正确执行它。
它的布局如下:
ConnectionPool pool = ConnectionPool.getInstance();
Connection connection = pool.getConnection();
PreparedStatement ps = null;
PreparedStatement rowsPs = null;
ResultSet rs = null;
ResultSet rowsRs = null;
String query = "SELECT SQL_CALC_FOUND_ROWS ...";
String totalRowsQuery = "SELECT FOUND_ROWS() AS RowCount";
try {
ps = connection.prepareStatement(query);
[set ps params]
rs = ps.executeQuery();
[process rs]
rowsPs = connection.prepareStatement(totalRowsQuery);
rowsRs = rowsPs.executeQuery();
[process rowsRs]
} catch (SQLException e) {
[handle e]
} finally {
DBUtil.closeResultSet(rs);
[close rowsRs]
[close ps]
[close rowsPs]
[close connection]
}
DBUtils 方法的一个例子是:
public static void closeResultSet(ResultSet rs)
{
try
{
if (rs != null)
rs.close();
}
catch (SQLException sqle)
{
sqle.printStackTrace();
}
}
这种方法的总体布局看起来不错吗?我应该以不同的方式处理连接吗?还是其他导致错误被记录的方法?
谢谢。
其他信息
我也收到了SQLException:
java.sql.SQLException: Connection com.mysql.jdbc.JDBC4Connection@[some number] is closed
在线:rowsPs = connection.prepareStatement(totalRowsQuery);
意味着在某处之前,连接已关闭。
我没有在任何地方明确关闭连接。
是否有可能调用的其他一些数据访问方法以某种方式关闭了此方法中的连接? (pool.getConnection() 打电话给dataSource.getConnection())
更新: 我已尝试按照建议使用 try-with-resources,但问题仍然存在。
上面第一个代码sn-p中引用的ConnectionPool类:
public class ConnectionPool
{
private static ConnectionPool pool = null;
private static DataSource dataSource = null;
public synchronized static ConnectionPool getInstance()
{
if ( pool == null ) {
pool = new ConnectionPool();
}
return pool;
}
private ConnectionPool()
{
try {
InitialContext ic = new InitialContext();
dataSource = (DataSource)
ic.lookup([jdbc/dbName]);
}
catch (Exception e) {
e.printStackTrace();
}
}
public Connection getConnection()
{
try {
return dataSource.getConnection();
}
catch (SQLException sqle) {
sqle.printStackTrace();
return null;
}
}
public void freeConnection(Connection c)
{
try {
c.close();
}
catch (SQLException sqle) {
sqle.printStackTrace();
}
}
}
更多来源: 我的池资源元素:
<Resource auth="Container" driverClassName="com.mysql.jdbc.Driver"
logAbandoned="true" maxActive="100" maxIdle="30" maxWait="10000"
removeAbandonedOnBorrow="true"
removeAbandonedTimeout="60" type="javax.sql.DataSource"
testWhileIdle="true" testOnBorrow="true"
validationQuery="SELECT 1 AS dbcp_connection_test"/>
更新:
我已经打开了慢查询日志,但是尽管再次抛出Exceptions,慢查询日志没有记录任何内容(没有查询需要超过 10 秒)。
所以看起来查询花费的时间不超过 60 秒。
仍然不确定是什么原因造成的。
【问题讨论】:
-
如果
finally中的一行失败了怎么办?不会执行任何下游线路。我只是关闭连接,因为所有健全的 JDBC 实现都会级联关闭其所有相关资源。 -
好的,谢谢。但它并没有真正找到问题的根源。您是否看到
finally子句中的行会失败的任何原因? -
是的,每一行都可能抛出异常。那种原因。
-
我会在我的日志中看到这些异常,不是吗?我打印它们。所有资源都通过一个 util 类关闭,该类围绕
try子句中的语句并在抛出异常时打印堆栈跟踪。 -
用
pool.getConnection()获得连接,用connection.close()释放连接,这是池的不变量。因此,您最好找出原因导致connection.close()行未到达或因异常而失败。或者,作为一个更奇特的解释,变量connection被重新分配,原来的连接被放弃了。
标签: java mysql jdbc connection-pooling