Hibernate保存时遇MySQL连接超时问题,求排查建议
首先,这个错误的核心原因是:你的连接池(c3p0)里的空闲连接被MySQL服务器主动断开了(因为超过了wait_timeout配置),但连接池还认为这些连接是可用的,当应用尝试使用这些失效连接时就会抛出超时错误。本地环境没出现问题,大概率是本地MySQL的wait_timeout配置更长,或者本地应用的连接使用率更高,空闲连接没机会达到超时阈值。
看了你当前的配置,确实有几个关键配置遗漏或者需要调整:
1. 依赖已弃用的JDBC自动重连属性,且c3p0不生效
你配置了hibernate.connection.autoReconnect和autoReconnectForPools,但这两个是MySQL Connector/J的旧属性,在8.0+版本的驱动中已经被弃用,而且c3p0作为连接池管理器,不会依赖JDBC的自动重连机制——它有自己的连接有效性校验体系,所以这两个配置其实起不到预期作用。
2. 缺少连接有效性测试的关键配置
虽然你设置了idle_test_period(3秒),但这个只是定期检测空闲连接,却没有配置连接取出/归还时的有效性校验,也没有指定测试连接的SQL语句。建议补充以下配置:
// 每次从连接池取出连接时测试有效性(性能略有开销,但能彻底避免失效连接问题) cfg.setProperty("hibernate.c3p0.testConnectionOnCheckout", "true") // 指定测试连接的SQL(MySQL用SELECT 1最轻便) .setProperty("hibernate.c3p0.preferredTestQuery", "SELECT 1");
如果担心testConnectionOnCheckout的性能影响,也可以改用testConnectionOnCheckin(归还连接时测试)配合idle_test_period:
cfg.setProperty("hibernate.c3p0.testConnectionOnCheckin", "true") .setProperty("hibernate.c3p0.preferredTestQuery", "SELECT 1");
3. 连接池空闲超时与MySQL的wait_timeout不匹配
你的hibernate.c3p0.timeout设置为30000毫秒(30秒),这个值是连接池销毁空闲连接的时间。你需要确保这个值小于MySQL服务器配置的wait_timeout,这样连接在被MySQL断开前,就会被连接池主动销毁并重建。
建议先查看生产环境MySQL的wait_timeout和interactive_timeout值(这两个建议保持一致):
SHOW VARIABLES LIKE 'wait_timeout'; SHOW VARIABLES LIKE 'interactive_timeout';
假设MySQL的wait_timeout是3600秒(1小时),那么可以把c3p0的timeout调整为3540000毫秒(59分钟),idle_test_period调整为300000毫秒(5分钟),确保连接池在MySQL断开前就清理掉空闲连接。
4. 额外注意:JSON大字段的影响
虽然当前错误是连接超时,但如果你的大JSON字段写入/读取耗时很长,可能会导致连接被长时间占用,间接导致其他空闲连接更容易达到超时阈值。如果存在这种情况,可以适当调整连接池的max_size,或者优化大JSON字段的操作(比如分块处理)。
总结下来,最关键的是移除无用的自动重连配置,添加连接有效性测试的配置,并确保连接池的空闲超时时间小于MySQL的wait_timeout。
内容的提问来源于stack exchange,提问作者elcharrua

