连接关闭不会关闭Tomcat中的连接

时间:2018-07-27 07:32:09

标签: java sql sql-server tomcat

在运行于Tomcat的Java Web项目中,两天后有超过4000个睡眠连接(我使用sp_who命令检查了它们)。完成数据库工作后,我确实关闭了所有语句,结果集和连接。我将以下模板用于数据库内容。

    try{
        this.openConnection();
        this.createStatement();

        // things ...

        this.cleanResources();
    }catch (SQLException e){
        this.cleanResources();
        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();
    }
}

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

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

每次执行sql代码后,具有休眠状态的行计数确实会增加,并且数据库填充会变得非常慢。为什么会发生?完成连接后,如何完全终止连接?真的是睡眠连接使我的SQL Server变慢了吗?

这是我的Tomcat配置(在context.xml中):

maxTotal="20" maxActive="20" maxIdle="20"

1 个答案:

答案 0 :(得分:1)

您用于清洁连接的代码/图案有缺陷:

try {
    this.openConnection();
    this.createStatement();

    // things ...

    this.cleanResources();
} catch (SQLException e){
    this.cleanResources();
    e.printStackTrace();
}

如果“事物”引发某些非SQLException或子类的异常,则不会关闭连接。

如果应该是

try {
    this.openConnection();
    this.createStatement();

    // things ...

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

然后这个:

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();
    }
}

如果rs.close()stmt.close()引发异常,则连接不会关闭。

应该是这样的:

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

在某些情况下,这些缺陷中的任何一个都可能导致数据库连接泄漏。

另一种可能性是您在代码中的某个地方没有遵循(有缺陷的)模式。

我认为您需要阅读以下内容:

  • Java 7+“尝试资源”支持
  • Java 1.0+“最终尝试...”。

还值得注意的是,以下做法是错误的做法:

  • 捕获Exception ...在大多数情况下
  • 壁球异常(即捕获并默默继续)...在大多数情况下
  • 在整个代码中分散调用printStackTrace。