Tomcat9+JSF2.9+Hibernate5.4.13环境下JdbcEnvironment创建失败问题
这个周期性出现的Hibernate JDBC环境创建失败问题,我在Tomcat+JSF+Hibernate的技术栈里遇到过很多次,大概率是数据库连接失效或者连接池配置不合理导致的——毕竟是隔几个小时/几天才爆发,不是启动就报错。下面给你一步步拆解排查和解决方法:
1. 先查MySQL的连接超时设置
MySQL默认的wait_timeout和interactive_timeout通常是8小时,但如果你的应用连接池里的空闲连接存活时间超过这个值,连接就会被MySQL主动断开,Hibernate尝试用失效连接创建JDBC环境时就会报错。
- 先登录MySQL执行这两句SQL,查看当前超时配置:
SHOW VARIABLES LIKE 'wait_timeout'; SHOW VARIABLES LIKE 'interactive_timeout'; - 如果这两个值小于你的应用连接池的空闲连接存活时间(比如你设置的
maxIdle对应的超时),建议调整MySQL的超时时间(比如设为28800秒即8小时,或者更长,匹配你的业务周期),同时一定要配合连接池的连接验证机制。
2. 优化Tomcat连接池的配置
Tomcat自带的DBCP连接池是大部分Java Web应用的选择,你需要在context.xml里正确配置连接验证,确保每次拿到的连接都是可用的。举个配置示例:
<Resource name="jdbc/YourDB" auth="Container" type="javax.sql.DataSource" driverClassName="com.mysql.cj.jdbc.Driver" url="jdbc:mysql://localhost:3306/your_db?useSSL=false&serverTimezone=UTC&autoReconnect=true" username="root" password="your_db_password" maxTotal="100" maxIdle="30" maxWaitMillis="10000" validationQuery="SELECT 1" testOnBorrow="true" testWhileIdle="true" timeBetweenEvictionRunsMillis="3600000" <!-- 每1小时检查一次空闲连接 --> minEvictableIdleTimeMillis="7200000" <!-- 空闲2小时后自动驱逐 --> removeAbandonedOnBorrow="true" removeAbandonedTimeout="60" />
关键配置的作用:
validationQuery="SELECT 1":用最简单的SQL验证连接是否存活testOnBorrow="true":每次获取连接时都验证,避免拿到失效连接testWhileIdle="true":定期检查空闲连接,提前剔除失效的autoReconnect=true:MySQL驱动层面的自动重连 fallback,配合连接池验证更稳妥
3. 检查Hibernate的连接池配置(如果用的是自带的)
如果你没使用Tomcat的全局连接池,而是用Hibernate自带的C3P0,一定要配置连接过期和验证逻辑,避免连接失效:
hibernate.connection.driver_class=com.mysql.cj.jdbc.Driver hibernate.connection.url=jdbc:mysql://localhost:3306/your_db?useSSL=false&serverTimezone=UTC hibernate.connection.username=root hibernate.connection.password=your_db_password hibernate.c3p0.max_size=100 hibernate.c3p0.min_size=10 hibernate.c3p0.timeout=1800 <!-- 30分钟超时,自动回收失效连接 --> hibernate.c3p0.idle_test_period=300 <!-- 每5分钟验证一次空闲连接 --> hibernate.c3p0.validate=true
注意:生产环境更推荐用Tomcat连接池或者HikariCP这类高性能、稳定的第三方连接池,比Hibernate自带的C3P0靠谱。
4. 排查JSF请求的连接泄漏问题
有时候JSF的ManagedBean里没有正确关闭Hibernate Session或者数据库连接,导致连接池被耗尽,后续请求拿不到连接就会触发这个错误。
- 确保在ManagedBean中,Hibernate Session是通过
@PostConstruct初始化,@PreDestroy关闭;如果用了Spring,尽量用声明式事务管理,避免手动管理连接。 - 检查是否有长时间运行的查询或者未关闭的资源,比如某些请求里打开了Session但没在finally块里关闭。
5. 一定要看完整的错误栈
这个Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]是一个包装异常,背后肯定有更具体的原因——比如Communications link failure(连接断开)、Access denied(权限问题)或者Connection pool exhausted(连接池耗尽)。
举个最常见的场景:如果日志里藏着
Communications link failure,那基本就是MySQL连接超时或者网络波动,结合上面的连接池验证配置就能解决。
内容的提问来源于stack exchange,提问作者ruydar

