Tomcat 8中Hibernate连接断管(Broken Pipe)问题排查求助
嘿,这个连接超时的问题我碰到过好多次了,咱们先拆解下原因,再给你具体的解决办法:
核心原因
你遇到的情况大概率是数据库端主动断开了长期闲置的连接,而你的C3P0连接池配置没有及时检测到这个变化。
很多数据库(比如MySQL、Oracle)都有连接超时的默认配置,比如MySQL的wait_timeout参数,如果一个连接闲置超过这个时间,数据库就会主动把它断开。你说的3-4小时无操作后失败,说明你的数据库超时设置应该就在这个区间。而你当前的hibernate.c3p0.idle_test_period=100(100秒)虽然会定期测试闲置连接,但如果这个测试周期比数据库的超时时间长,那连接被数据库踢掉之后,C3P0还没来得及检测,下次用的时候就会抛出连接失败的异常。
另外你的hibernate.c3p0.min_size=1,这个最小连接数意味着有一个连接会长期处于闲置状态,刚好命中了数据库的闲置超时规则。
具体解决步骤
1. 确认数据库的连接超时配置
先查一下你使用的数据库的闲置超时参数:
- 对于MySQL:执行
show variables like '%timeout%';,重点看wait_timeout和interactive_timeout的值,单位是秒。 - 对于Oracle:检查
SQLNET.EXPIRE_TIME参数,或者查看会话的闲置超时设置。
记录下这个超时时间,后续C3P0的配置要基于这个值调整。
2. 调整C3P0连接池配置
修改你的hibernate.cfg.xml,添加/调整以下参数:
- 缩短闲置连接测试周期:把
hibernate.c3p0.idle_test_period设置成比数据库超时时间短30-60分钟的值。比如如果数据库超时是4小时(14400秒),就设成12600(3.5小时),确保在数据库断开连接前,C3P0就能检测到并替换无效连接。<property name="hibernate.c3p0.idle_test_period">12600</property> - 开启连接校验:可以选择两种校验方式:
- 每次获取连接时校验(有轻微性能开销,适合对连接可靠性要求高的场景):
<property name="hibernate.c3p0.testConnectionOnCheckout">true</property> - 每次归还连接时校验(性能影响更小):
<property name="hibernate.c3p0.testConnectionOnCheckin">true</property>
<property name="hibernate.c3p0.preferredTestQuery">SELECT 1</property> - 每次获取连接时校验(有轻微性能开销,适合对连接可靠性要求高的场景):
- 设置连接最大闲置时间:让C3P0主动回收超过时间的闲置连接,避免被数据库踢掉:
<property name="hibernate.c3p0.maxIdleTime">13000</property> <!-- 比数据库超时短一些 -->
3. 关于内存监控代码的说明
你提到的内存监控代码(Runtime runtime = Runtime.getRuntime(); long freeMemory = runtime.freeMemory();)和当前的连接失败问题关联性不大,除非你的应用出现严重内存泄漏导致连接池无法正常工作。如果后续调整连接池配置后问题仍存在,再考虑排查内存相关问题。
如果你的异常栈里包含Broken pipe、Connection reset by peer或者No operations allowed after connection closed这类关键词,就完全能确认是数据库断开闲置连接的问题了。
内容的提问来源于stack exchange,提问作者Ekaterina Ivanova iceja.net




