Java ConnectionPool连接未关闭,卡在“睡眠”中

Java ConnectionPool连接未关闭,卡在“睡眠”中,java,database,tomcat,Java,Database,Tomcat,我有一个webapp,它使用JNDI查找来连接数据库 连接工作正常,返回查询时没有问题。根据mysql管理员的说法,这个问题告诉我们连接没有正确关闭,并且处于“睡眠”模式。这意味着它们变得不可用,然后我就没有连接了 有没有人能给我一些建议,告诉我怎样才能使连接成功地返回到池中 public class DatabaseBean { private static final Logger logger = Logger.getLogger(DatabaseBean.class); privat

我有一个webapp,它使用JNDI查找来连接数据库

连接工作正常,返回查询时没有问题。根据mysql管理员的说法,这个问题告诉我们连接没有正确关闭,并且处于“睡眠”模式。这意味着它们变得不可用,然后我就没有连接了

有没有人能给我一些建议,告诉我怎样才能使连接成功地返回到池中

public class DatabaseBean {

private static final Logger logger = Logger.getLogger(DatabaseBean.class);

private Connection conn;
private PreparedStatement prepStmt;

/**
 * Zero argument constructor
 * Setup generic databse connection in here to avoid redundancy
 * The connection details are in /META-INF/context.xml
 */
public DatabaseBean() {
    try {
        InitialContext initContext = new InitialContext();
        DataSource ds = (DataSource) initContext.lookup("java:/comp/env/jdbc/mysite");
        conn = ds.getConnection();
    }
    catch (SQLException SQLEx) {
        logger.fatal("There was a problem with the database connection.");
        logger.fatal(SQLEx);
        logger.fatal(SQLEx.getCause());
    }
    catch (NamingException nameEx) {
        logger.fatal("There was a naming exception");
        logger.fatal(nameEx);
        logger.fatal(nameEx.getCause());
    }
}

/**
 * Execute a query. Do not use for statements (update delete insert etc).
 *
 * @return A ResultSet of the execute query. A set of size zero if no results were returned. It is never null.
 * @see #executeUpdate() for running update, insert delete etc.
 */

public ResultSet executeQuery() {
    ResultSet result = null;
    try {
        result = prepStmt.executeQuery();
        logger.debug(prepStmt.toString());
    }
    catch (SQLException SQLEx) {
        logger.fatal("There was an error running a query");
        logger.fatal(SQLEx);
    }
    return result;
}
剪断

这在使用数据库连接的javabean中

public LinkedList<ImportantNoticeBean> getImportantNotices() {

    DatabaseBean noticesDBBean = new DatabaseBean();
    LinkedList<ImportantNoticeBean> listOfNotices = new LinkedList<ImportantNoticeBean>();

    try {
        PreparedStatement preStmt = noticesDBBean.getConn().prepareStatement("SELECT pseudonym, message, date_to, date_from " +
                "FROM importantnotices, users " +
                "WHERE importantnotices.username = users.username " +
                "AND NOW() >= date_from AND NOW() <= date_to;");

        noticesDBBean.setPrepStmt(preStmt);
        ResultSet result = noticesDBBean.executeQuery();

        while (result.next()) {
            ImportantNoticeBean noticeBean = new ImportantNoticeBean();

            noticeBean.setAuthor(result.getString("pseudonym"));
            noticeBean.setMessage(result.getString("message"));
            noticeBean.setDateTo(result.getDate("date_to"));
            noticeBean.setDateFrom(result.getDate("date_from"));

            listOfNotices.add(noticeBean);
        }

        result.close();

    } catch (SQLException SQLEx) {
        logger.error("There was an error in ImportantNoticesBean.getImportantNotices()");
        logger.error(SQLEx);
    } finally {
        noticesDBBean.close();
    }
    return listOfNotices;
}

<Context reloadable="true">

    <Resource name="jdbc/mysite"
              auth="Container"
              type="javax.sql.DataSource"
              username="user"
              password="password"
              driverClassName="com.mysql.jdbc.Driver"
              url="jdbc:mysql://localhost:3306/mysite"
              maxActive="10"
              maxIdle="5"
              maxWait="6000"
              removeAbandoned="true"
              logAbandoned="false"
              removeAbandonedTimeout="20"
            />
</Context>

您似乎正确地关闭了连接-除了prepsmt.close抛出SQLException的情况外,我找不到连接泄漏

您使用的是什么池实现?当您关闭连接时,池不需要立即关闭底层MySQL连接——毕竟这就是连接池的意义所在!所以从MySQL的角度来看,连接看起来是活动的,尽管你的应用程序没有使用任何连接;它们可能只是由TC连接池持有

您可能需要尝试连接池的设置。请在系统空闲时让它收缩连接池。或者,让它定期刷新所有连接。或者,对从MySQL等获得的并发连接数有一个严格的上限


检查代码是否存在连接泄漏的一种方法是强制ds.getConnection始终打开一个新的物理连接,如果您的连接池具有这些设置,则强制conn.close释放连接。然后,如果您观察MySQL端的连接,您可能会发现代码是否真的存在连接泄漏。

有一点@binil没有注意到,在出现异常的情况下,您不会关闭结果集。这可能会导致连接保持打开状态,具体取决于驱动程序的实现。将result.close调用移动到finally块

这是一个类似的问题-

这是我对那个问题的回答,它解决了另一个人的问题。它可能也会帮助你

DBCP使用Jakarta Commons数据库连接池。它依赖于雅加达公共设施组件的数量:

* Jakarta-Commons DBCP
* Jakarta-Commons Collections
* Jakarta-Commons Pool
我正在使用相同的连接池功能,我正在设置这些属性,以防止类似的事情发生——它只是没有通过tomcat进行配置。 但是如果第一件事不起作用,试试这些

testWhileIdle=true
timeBetweenEvictionRunsMillis=300000

好的,我可以把这个整理一下。我已将数据库配置资源更改为以下内容:

*SNIP*
maxActive="10"
maxIdle="5"
maxWait="7000"
removeAbandoned="true"
logAbandoned="false"
removeAbandonedTimeout="3"
*SNIP*
目前这已经足够有效了。现在发生的事情是,一旦我达到10个连接,Tomcat就会检查空闲时间>3的废弃连接。每次达到最大连接数时,它都会在批处理作业中执行此操作。潜在的问题是,如果我需要同时运行10个以上的查询,这不是我独有的。重要的是RemoveBandonedTimeout小于maxWait


这是应该发生的吗?这是游泳池的运作方式吗?如果至少在我看来,你会等到连接中断后再修复,而不是一开始就不让它“中断”。也许我还没有明白。

我正在使用与您相同的配置。如果mysql administratorwindows中的连接显示它处于睡眠模式,则表示该连接已被池化,但未被使用。我在运行一个测试程序时检查了这个问题,多个线程对Mysql进行随机查询。如果有帮助,以下是我的配置:

        defaultAutoCommit="false"
        defaultTransactionIsolation="REPEATABLE_READ"
        auth="Container"
        type="javax.sql.DataSource"
        logAbandoned="true" 
          removeAbandoned="true"
        removeAbandonedTimeout="300" 
        maxActive="-1"
        initialSize="15"
        maxIdle="10"
        maxWait="10000" 
        username="youruser"
        password="youruserpassword"
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://yourhost/yourdatabase"/>
该问题告诉我们连接未正确关闭,并且卡在“睡眠”模式下

这实际上只对了一半

我遇到的问题实际上是每个应用程序都定义了一个到数据库服务器的新连接。因此,每次我关闭所有连接时,应用程序A都会根据其WEB.xml配置文件创建一组新连接,并愉快地运行。应用程序B也会这样做。问题在于,它们是独立的池,试图达到服务器定义的限制。我想这是一种比赛状态。因此,当应用程序A完成连接时,它会坐在那里等待再次使用它们,直到超时时间过去,而现在需要连接的应用程序B被拒绝资源,即使应用程序A已完成连接,并且应该返回池中。一旦超时时间过去,连接将被释放,B或C等可以再次访问它

e、 g.如果限制为10 mySQL配置文件限制,并且每个应用程序已配置为最多使用10次,则将有20次连接尝试。显然,这是一个糟糕的情况

解决方法是使用RTFM并将。这确实让共享发布变得很痛苦,但是有一些方法可以解决,比如从上下文链接到其他xml文件


明确地说:我将每个应用程序的连接详细信息都放在WEB.xml中,并为此进行了斗争。

我认为当创建RS的PS关闭时,RS总是会关闭
当生成ltSet对象的语句对象被关闭、重新执行或用于从一系列多个结果中检索下一个结果时,ltSet对象将自动关闭。如果您可以编辑您的答案并解释RemoveBandonedTimeout小于maxWait的重要性,那就太好了:-我还没有足够的cred进行编辑,soz。
        defaultAutoCommit="false"
        defaultTransactionIsolation="REPEATABLE_READ"
        auth="Container"
        type="javax.sql.DataSource"
        logAbandoned="true" 
          removeAbandoned="true"
        removeAbandonedTimeout="300" 
        maxActive="-1"
        initialSize="15"
        maxIdle="10"
        maxWait="10000" 
        username="youruser"
        password="youruserpassword"
        driverClassName="com.mysql.jdbc.Driver"
        url="jdbc:mysql://yourhost/yourdatabase"/>