5

我们看到我们的数据库连接因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();
4

2 回答 2

11

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

  1. 连接池保持连接打开的时间过长。
  2. 数据库在太短的时间后关闭连接。

从理论上讲,增加/减少两边的超时以对齐它应该可以解决问题。

在 DBCP 上,最好的办法是在通过 atestOnBorrow=true和 avalidationQuery设置返回之前验证连接,例如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在块中尽可能短的范围内关闭所有数据库资源。然而,可以配置一个不错的连接池来获取废弃的连接,但这绝对不应该用作“解决方法”。

于 2011-09-08T15:46:02.453 回答
1

我也面临同样的问题。然后我意识到我正在进行多个导致问题的异步 ajax 调用。

我对这些调用进行了序列化,它解决了这个问题。

于 2017-04-25T18:59:50.080 回答