DBCP返回关闭的连接


问题内容

我们看到的情况是,我们的数据库连接由于org.apache.commons.dbcp.BasicDataSource套接字写入错误而终止:

com.microsoft.sqlserver.jdbc.SQLServerException: Connection reset by peer: socket write error

当然,所有随后的写入连接的尝试都会失败:

com.microsoft.sqlserver.jdbc.SQLServerException: The connection is closed.

在更新代码以捕获此类异常并在发生连接时请求新连接后,该连接再次失败。我是否怀疑DataSource#getConnection()每次调用实际上都不在提供新的连接?难道不只是重用已关闭的现有连接吗?

如果我是正确的,那么丢弃旧的连接并请求新的连接的正确方法是什么?

编辑:这是我想知道的更简洁的版本:

Connection c1, c2;
c1 = DatabaseManager.getConnection();
// c1.close() not called
c2 = DatabaseManager.getConnection();

“ c1 == c2”是正确的说法吗?还是分配了两个连接?如果是后者,则将这样的代码表示“连接池泄漏”:

Connection c1;
c1 = DatabaseManager.getConnection();
// c1.close() not called
c1 = DatabaseManager.getConnection();

问题答案:

池连接已被数据库关闭。这可能意味着两件事:

  1. 连接池使连接打开时间过长。
  2. DB在过短的时间后关闭连接。

从理论上讲,增加/减少双方的超时以使其一致可以解决该问题。

在DBCP上,最好的选择是在通过testOnBorrow=truevalidationQuery设置返回之前验证连接,例如SELECT 1。您可以在Tomcat JDBC数据源文档中找到配置选项。


更新 按照您的更新:

这是我想知道的更简洁的版本:

Connection c1, c2;
c1 = DatabaseManager.getConnection();
// c1.close() not called
c2 = DatabaseManager.getConnection();

“ c1 == c2”是正确的说法吗?还是分配了两个连接?

这是两个不同的连接。仅当您致电时,c1.close()才有可能c2返回相同的连接。

如果是后者,则将这样的代码表示“连接池泄漏”:

Connection c1;
c1 = DatabaseManager.getConnection();
// c1.close() not called
c1 = DatabaseManager.getConnection();

是的,因为它永远不会返回到池中,因此肯定会泄漏第一个连接。您应该 始终 在一个try- finally块中以尽可能短的范围关闭所有数据库资源。但是,可以配置一些不错的连接池以获取废弃的连接,但是,绝对不应该将其用作“替代方法”。