【问题标题】:Connection.close() does not closes the connection, it make it sleep forever?Connection.close() 不关闭连接,它让它永远休眠?
【发布时间】:2019-02-01 20:48:53
【问题描述】:

在我使用 java 编写并使用 tomcat 和 sql server 的 Web 应用程序中,我无法通过键入 connection.close() 来关闭数据库连接。当我将 sp_who 写入 SSMS 时,我可以看到当我的应用程序执行 sql 操作时,我打开的睡眠连接数增加了。

示例代码如下:

BaseRepository baseRepository = new BaseRepository();
try{
    baseRepository.createStatement();

    baseRepository.stmt.executeUpdate("update AutoRunURLs set STATUS = 0");

}catch (SQLException e){
    e.printStackTrace();
}finally {
    baseRepository.cleanResources();
}

这是我上面使用的其他功能:

public void openConnection() {
    try {
        this.conn = ds.getConnection(); // ds is an instance of javax.sql.DataSource
        this.isOpen = true;
    } catch (Exception e) {
        e.printStackTrace();
    }
}

 public void createStatement() {
    try {
        if (!this.isOpen) this.openConnection();
        this.stmt = this.conn.createStatement();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public void cleanResources() {
    try {
        if (this.rs != null) {
            rs.close();
            this.rs = null;
        }
        if (this.stmt != null) {
            stmt.close();
            this.stmt = null;
        }
        if (this.conn != null) {
            this.closeConnection();
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (this.conn != null) this.closeConnection();
    }
}

 public void closeConnection() {
    try {
        if (this.conn != null){
            this.conn.close();
        }
        this.isOpen = false;
    } catch (Exception e) {
        e.printStackTrace();
    }
}

当我运行上面以BaseRepository baseRepository ... 开头的第一部分时,会出现一个睡眠连接,我在输入 sp_who 时看到它并没有关闭(我等了大约一天)。这是为什么?我该如何防止这种情况发生?

我还有一种情况。在我的 tomcat 配置中,我将“maxIdle”值设置为 10,但即使在一周后,睡眠连接也会增加到数千。为什么 maxIdle 不起作用?我是这样设置的:

<Context>

<!-- Default set of monitored resources. If one of these changes, the    -->
<!-- web application will be reloaded.                                   -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<Resource auth="Container" driverClassName="net.sourceforge.jtds.jdbc.Driver" maxTotal="999999" maxIdle="10" "Database info here..." validationQuery="select 1"/>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->

我该如何解决这些问题?问候,


编辑:我实际上是通过创建一个计划任务来管理它,该任务每 x 分钟运行一次,并终止睡眠超过 y 分钟的睡眠连接。但这不是我想要的方式。任何其他解决方案都会很棒。

【问题讨论】:

  • DB 连接和该连接的 Java 资源是分开的,在代码中您只是关闭该 db 连接资源的 java ref,实际需要在 DB 中处理该资源的操作由 DB 处理。在您的级别上,您可以在 tomcat 级别或数据源级别更改最大数据库连接数以控制您的非活动会话数
  • @NishantModi 感谢您的回答。通过这样做,例如,如果将 maxTotal 设置为 100,然后在睡眠连接达到 100 之后,应用程序不会像我们预期的那样响应。所以不能绑定了,还能怎么办?
  • 休眠连接并不意味着他们不会处理请求。睡眠连接将在需要时被激活并提供给应用程序。如果这不是您的情况并且应用程序没有获得连接,那么肯定还有其他问题导致了这种情况。
  • @NishantModi 是的,显然还有其他一些问题。那么它可能是什么?
  • 你确定应用程序没有连接

标签: java sql-server jdbc tomcat8


【解决方案1】:

您正在使用 Tomcat 中内置的连接池。这意味着它保持连接打开以供重用。当您关闭代码中的连接时,它们实际上并没有关闭,而是返回到池中以供您的应用程序重新使用。这会提高效率,因为打开新连接需要时间。

换句话说,没有任何问题,保持打开的连接是预期的行为。

您可能希望将您的 maxTotal 减少到更合理的值,例如 10 - 20 而不是 999999。

顺便说一句,您处理连接的方式有点奇怪,并且很容易泄漏连接。您可能只想在真正需要时从数据源获取连接,并了解 try-with-resources 以便尽快关闭它。

【讨论】:

  • 感谢您的回答。每当我完成它时,我都会关闭连接。但正如我上面提到的评论,tomcat 不会以某种方式重用睡眠连接。因此,将 maxTotal 设为 10-20 将导致不响应任何请求。还有一个你错过的问题。我说睡眠连接数增加到数千。那么 Tomcat 真的会随时准备好提供数千个连接吗?很明显,这里还有其他问题。但无法找出它是什么。
  • @JollyRoger 那么你处理关闭连接的方式可能是错误的和泄漏连接。
  • 这就是为什么我写了我如何处理关闭连接情况的方式。你能看到那里有泄漏吗?
  • @JollyRoger 如果您直接从数据源获取连接并使用 try-with-resources 而不是在连接 + 语句周围使用这样的包装器,那么您的代码会简单得多。您显示的代码似乎没有泄漏连接,但您描述的问题表明您正在泄漏连接。
  • 是的,绝对有泄漏,但由于这段代码不属于我,不幸的是我无法做出很大的改变。连接泄漏的其他原因可能是什么?
猜你喜欢
  • 2013-09-05
  • 1970-01-01
  • 1970-01-01
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
  • 2011-11-04
  • 2011-04-27
相关资源
最近更新 更多