使用 c3p0 连接池丢失 MySQL 连接

Posted

技术标签:

【中文标题】使用 c3p0 连接池丢失 MySQL 连接【英文标题】:Loosing MySQL connections with c3p0 connection pool 【发布时间】:2019-12-31 22:34:54 【问题描述】:

我们正在使用休眠和 mysql。我们使用 c3p0 创建一个连接池。根据我的研究,我在我的 persistence.xml 文件中提出了以下这些设置。 据我了解,数据库连接数不应低于最小值 10,当连接时间达到 14400(4 小时)时,它将被关闭并重新连接。

<property name="hibernate.c3p0.min_size" value="10" />
<property name="hibernate.c3p0.max_size" value="100" />
<property name="hibernate.c3p0.acquire_increment" value="10" />
<property name="hibernate.c3p0.max_statements" value="1000" />
<property name="hibernate.c3p0.numHelperThreads" value="30" />
<property name="hibernate.c3p0.timeout" value="14400" />
<property name="hibernate.c3p0.maxIdleTimeExcessConnections" value="1800" />
<property name="hibernate.c3p0.validate" value="false" />
<property name="hibernate.c3p0.idle_test_period" value="3600" />
<property name="hibernate.c3p0.preferredTestQuery" value="select id from contact limit 1" />
<property name="hibernate.c3p0.acquireRetryAttempts" value="100" />
<property name="hibernate.c3p0.acquireRetryDelay" value="1000" />
<property name="hibernate.c3p0.breakAfterAcquireFailure" value="true" />

使用这个查询我监控连接。我看到连接数从 10 开始,对于空闲连接,处理时间爬升到 3600 并根据 idle_test_period 重置。但是过了一天左右,我再次检查,发现连接数减少到 9。到周末连接数下降到 6。当连接数达到 1 时,程序将锁定而不抛出尝试运行数据库查询时出现异常。

SELECT 
    performance_schema.threads.PROCESSLIST_ID,
    performance_schema.threads.PROCESSLIST_USER,
    performance_schema.threads.PROCESSLIST_HOST,
    performance_schema.threads.PROCESSLIST_TIME
FROM performance_schema.threads
WHERE performance_schema.threads.PROCESSLIST_USER = 'loginname'
ORDER BY performance_schema.threads.PROCESSLIST_HOST, performance_schema.threads.PROCESSLIST_TIME;

正如我所说,空闲连接的 PROCESS_TIME 上升到 3600,但昨天我看到一个爬升到超过 17000,到第二天早上连接被关闭,我的连接总数下降到 5 个。

这里有什么我遗漏的吗?打开的连接是否应该保持在至少 10 个?这些设置中是否存在使连接无法保持打开或保持的东西?

【问题讨论】:

【参考方案1】:

您很可能有Connection 泄漏,也就是说,您的应用程序有时无法在它检出的连接上调用close()

c3p0 通常不会干扰已检出并受客户端控制的连接。特别是,hibernate.c3p0.timeout (c3p0.maxIdleTime) 将不会被强制执行,因此最终泄露的连接将在 mysql 端超时,但从 c3p0 的角度来看将永远保持使用状态。最终,所有连接都将被检出但已失效,并且新客户端将无限期挂起(除非设置了c3p0.clientTimeout),等待永远不可用的连接。

您的帖子中唯一与此假设不一致的是您将hibernate.c3p0.max_size (c3p0.maxPoolSize) 设置为 100,因此您在签出 100 个连接时冻结,而不仅仅是 10 个,除非有服务器-side 限制被强制执行。但是由于您正在查看服务器端打开的连接,这些连接和客户端打开的连接之间的映射并不清楚,因为您只看到已打开但尚未超时的连接。但是,如果您从未看到超过 10 个打开的连接,我仍然会感到非常惊讶。

不过,我要做的第一件事是调试或至少解决连接泄漏问题。 c3p0 的 never-mess-with-a-checked-out-connection 规则的主要例外是 unreturnedConnectionTimeout,您可以将其配置为 hibernate.c3p0.unreturnedConnectionTimeout。它将关闭已签出但在您定义的时间过长后未返回的连接。

不过,最好是消除连接泄漏,而不仅仅是解决它们。当您还设置unreturnedConnectionTimeout 时,将配置属性debugUnreturnedConnectionStackTraces(您将配置为hibernate.c3p0.debugUnreturnedConnectionStackTraces)设置为true,并且生成永远不会关闭的连接的堆栈跟踪将打印到您的日志中。然后您可以尝试了解导致某些连接打开但从未关闭的代码路径。通常它与不使用对所有Exception-al 案例都健壮的Connection.close() 策略有关。在 Java 7 之后,try-with-resources 构造非常有助于解决这个问题。

【讨论】:

以上是关于使用 c3p0 连接池丢失 MySQL 连接的主要内容,如果未能解决你的问题,请参考以下文章

在tomcat上与hibernate和mysql共享c3p0连接池

Mysql----JDBC 连接池 DBCP C3P0

关于c3p0连接池连接mysql数据库需要注意的几点

Hibernate c3p0 连接池不会超时空闲连接

网络协议 finally{ return问题 注入问题 jdbc注册驱动问题 PreparedStatement 连接池目的 1.2.1DBCP连接池 C3P0连接池 MYSQL两种方式进行实物管

使用 c3p0 连接数据库