【问题标题】:Tomcat8 + c3p0, connections are being interruped and auto closedTomcat8 + c3p0,连接被中断并自动关闭
【发布时间】:2016-01-13 12:43:15
【问题描述】:

我正在使用 Maven 在 Tomcat 8 上开发一个 Web 应用程序,我正在使用 c3p0 来处理主线程和其他 2 个并发线程上的连接,我的连接管理器类正在询问我已经实现的 DataSource 单例类同步连接,像这样

public synchronized Connection getConnection() {
    try {
        return cpds.getConnection();
    } catch (SQLException ex) {
        logger.error("Error while issuing a pooled connection", ex);
    }
    return null;
}

,但是当我尝试使用这些连接时,它们会开始中断

09:47:17.164 [QuartzScheduler_Worker-4] ERROR com.myapp.providers.DataSource - Error while issuing a pooled connection
java.sql.SQLException: An SQLException was provoked by the following failure: java.lang.InterruptedException
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106) ~[c3p0-0.9.1.2.jar:0.9.1.2]
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:65) ~[c3p0-0.9.1.2.jar:0.9.1.2]
    at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:62) ~[c3p0-0.9.1.2.jar:0.9.1.2]
    at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:531) ~[c3p0-0.9.1.2.jar:0.9.1.2]
    at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128) ~[c3p0-0.9.1.2.jar:0.9.1.2]

或在事务中间关闭并破坏当时正在使用的任何语句和结果集

我正在像这样配置 DataSource 对象

cpds = new ComboPooledDataSource();
        cpds.setDriverClass(oracle.jdbc.driver.OracleDriver);
        cpds.setJdbcUrl(jdbc:oracle:thin:@xx.xxx.xxx.xxx:1521:XE);
        cpds.setUser("username");
        cpds.setPassword("password");

        // database connection properties
        cpds.setInitialPoolSize(10);
        cpds.setAcquireIncrement(3);
        cpds.setMaxPoolSize(100);
        cpds.setMinPoolSize(15);
        cpds.setMaxStatements(75);

        // connection pool preferences
        cpds.setIdleConnectionTestPeriod(60);
        cpds.setMaxIdleTime(30000);
        cpds.setAutoCommitOnClose(false);
        cpds.setPreferredTestQuery("SELECT 1 FROM DUAL");
        cpds.setTestConnectionOnCheckin(false);
        cpds.setTestConnectionOnCheckout(false);
        cpds.setAcquireRetryAttempts(30);
        cpds.setAcquireRetryDelay(1000);
        cpds.setBreakAfterAcquireFailure(false);

我还编写了一个小测试方法,它在循环中运行并查询数据库 n 次,但效果很好。

【问题讨论】:

  • 你的 crp0 配置在哪里?
  • 我正在以编程方式对其进行配置,我将在几秒钟内对其进行编辑
  • 在@Steve Waldman 的回答中,他指向了一个已挂起的线程,那么您是否使用不同的线程打开连接并使用连接?如果你在一个线程中使用连接,当另一个线程从池中请求连接时,它不知道上下文(意味着 tomcat 不知道它的存在),tomcat 会积极地中断第一个线程以将连接传递给第二个线程
  • 如果这是一个新项目,我建议你放弃这种体力劳动。无需自行打开/关闭连接。有很多项目可以为您完成这项工作。查看this。使用这些项目中的任何一个,您所做的就是设置 DataSource 并传递给某个特定的类,然后可用于执行数据库操作。另外,我不会使用 c3p0,而是选择HikariCP
  • 这不是一个新项目,我也没有在这两个线程上完成所有工作。在某些情况下,我会在 Jersey2 端点中打开一个连接(即返回 GET 响应)

标签: java maven c3p0 tomcat8


【解决方案1】:

c3p0-0.9.1.2 非常非常老了;请考虑升级到当前的生产版本 0.9.5.1。

问题既清楚又不那么清楚。明确的部分是在等待获取连接的客户端线程上调用interrupt()。不太清楚的部分是谁在这样做以及为什么这样做。

猜测是 Tomcat 本身正在这样做,因为客户端线程挂起的时间太长。如果线程挂在getConnection(),那可能是由于连接泄漏和池耗尽。我们在上面看到了您如何获得连接。您是否对确保它们在 finally 块中可靠地close()ed 保持警惕?

您可能会尝试设置checkoutTimeout,例如

cpds.setCheckoutTimeout( 5000 ); // 5 secs

如果连接结帐挂起,这实际上并不能解决问题。但是,您将看到 c3p0 TimeoutExceptions 而不是由神秘中断引发的问题。不过,这将验证问题是否在结帐时长时间挂起,这很可能是由于连接泄漏(缺少对 close() 的调用)或仅仅是由于 maxPoolSize 值太低而导致池耗尽加载。

如果似乎确实存在连接泄漏,请参阅unreturnedConnectionTimeoutdebugUnreturnedConnectionStackTraces 以帮助追踪它。另见"Configuring to Debug and Workaround Broken Client Applications"

【讨论】:

  • 我注意到旧版本并升级了。问题仍然存在。听从您的建议,我设置了 setCheckoutTimeout(500) 并得到: java.sql.SQLException: 客户端检出连接的尝试已超时。例外。游泳池很快就用完了,我猜这可能是问题所在。
  • (我会尝试 5000 而不是 500 毫秒。通常连接应该在 500 毫秒内检出,但如果池暂时耗尽,因为它需要扩展或因为其他客户端正在使用连接但很快就会返回它们,可以想象你偶尔会看到这种延迟。我怀疑它不会有太大的不同,你仍然会看到超时。)
  • unreturnedConnectionTimeoutdebugUnreturnedConnectionStackTraces 对于查找连接泄漏非常非常有帮助。)
  • 设置为 5000 什么都没有,添加了 unreturnedConnectionTimeoutdebugUnreturnedConnectionStackTraces,我只得到 InterruptedException's
  • 你设置了什么unreturnedConnectionTimeout
猜你喜欢
  • 1970-01-01
  • 2017-01-16
  • 1970-01-01
  • 1970-01-01
  • 2018-11-10
  • 2014-05-02
  • 2011-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多