DBCP返回已关闭的连接

Jim*_*ell 5 java jdbc apache-commons-dbcp

我们看到我们的数据库连接因org.apache.commons.dbcp.BasicDataSource插槽写入错误而死的情况:

com.microsoft.sqlserver.jdbc.SQLServerException: Connection reset by peer: socket write error
Run Code Online (Sandbox Code Playgroud)

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

com.microsoft.sqlserver.jdbc.SQLServerException: The connection is closed.
Run Code Online (Sandbox Code Playgroud)

更新代码以捕获此类异常并在发生新连接时请求它,它再次失败.我是否正确怀疑DataSource#getConnection()每次呼叫时呼叫实际上并没有提供新的连接?是不是只是重用现有的连接,这是关闭的?

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

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

Connection c1, c2;
c1 = DatabaseManager.getConnection();
// c1.close() not called
c2 = DatabaseManager.getConnection(); 
Run Code Online (Sandbox Code Playgroud)

"c1 == c2"是真实的陈述吗?或者分配了两个连接?如果是后者,那么像这样的代码表示"连接池泄漏":

Connection c1;
c1 = DatabaseManager.getConnection();
// c1.close() not called
c1 = DatabaseManager.getConnection();
Run Code Online (Sandbox Code Playgroud)

Bal*_*usC 10

汇总连接已由DB关闭.这可能意味着两件事:

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

从理论上讲,增加/减少任何一方的超时以对齐它应该可以解决问题.

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


更新按照您的更新:

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

Connection c1, c2;
c1 = DatabaseManager.getConnection();
// c1.close() not called
c2 = DatabaseManager.getConnection(); 
Run Code Online (Sandbox Code Playgroud)

"c1 == c2"是真实的陈述吗?或者分配了两个连接?

这是两个截然不同的联系.只有当你打电话时c1.close()才有合理的机会c2返回相同的连接.

如果是后者,那么像这样的代码表示"连接池泄漏":

Connection c1;
c1 = DatabaseManager.getConnection();
// c1.close() not called
c1 = DatabaseManager.getConnection();
Run Code Online (Sandbox Code Playgroud)

是的,肯定会泄漏第一个连接,因为它从未被返回到池中.您应始终try-finally块中以尽可能短的范围关闭所有数据库资源.然而,有点像样的连接池可以配置以获得废弃的连接,但这绝对不能用作"解决方法".

  • 如果你从不调用`Connection#close()`(以及`Statement#close()` 和`ResultSet#close()`),那么你的应用程序就会有更大的问题。关闭池连接会将其返回到池中。不这样做会累积连接,直到数据库用完它们(这反过来可能会强制关闭旧连接以回收它们)。另见 http://stackoverflow.com/questions/5602772/how-often-should-statement-and-resultset-objects-be-closed-in-jdbc 和 http://stackoverflow.com/questions/2313197/jdbc- mysql-connection-pooling-practices/ (2认同)