Spring Boot 1.5.6应用数据库重启后带@Transactional注解的服务报错求助
问题分析与解决方案
这个问题我之前在基于Spring Boot的项目里也碰到过,核心原因很明确:数据库重启后,Tomcat JDBC连接池里的旧连接已经失效,但带@Transactional注解的事务方法复用了这些无效连接;而不带注解的DAO调用因为走了连接池的常规获取流程,触发了连接有效性校验,所以能正常工作。
核心原因拆解
当数据库重启时,连接池里之前建立的物理连接都会被数据库端关闭,但连接池本身无法感知这个变化。针对两种场景的差异:
- 带
@Transactional的方法:Spring事务管理器会复用上下文里的EntityManager,而EntityManager持有的是连接池中已失效的旧连接,事务启动时直接使用这个无效连接,就会抛出“连接已关闭”的异常。 - 不带
@Transactional的DAO调用:每次调用都会从连接池重新获取连接,若连接池配置了有效性校验,会自动剔除失效连接并新建有效连接,因此不会报错。
具体解决方案
1. 配置Tomcat JDBC连接池的连接有效性校验参数
这是最根本的解决方法,让连接池自动检测并剔除失效连接。在你的application.properties或application.yml中添加以下针对SQL Server的配置:
# 从连接池获取连接时强制校验有效性 spring.datasource.tomcat.test-on-borrow=true # SQL Server专用的连接校验语句(快速执行的轻量SQL) spring.datasource.tomcat.validation-query=SELECT 1 # 校验间隔(30秒),避免每次获取连接都校验,平衡性能与可靠性 spring.datasource.tomcat.validation-interval=30000 # 空闲时也校验连接,提前剔除失效连接 spring.datasource.tomcat.test-while-idle=true # 空闲连接的校验周期(60秒) spring.datasource.tomcat.time-between-eviction-runs-millis=60000 # 连接空闲超过30分钟就销毁 spring.datasource.tomcat.min-evictable-idle-time-millis=1800000
2. 确认自定义事务管理器的数据源配置
你使用了自定义的CHILD_TRANSACTION_MANAGER,一定要确保这个事务管理器关联的DataSource已经正确应用了上述连接池配置,不要只配置了默认数据源而遗漏了自定义数据源的参数。
3. 兜底方案:异常重试(可选)
如果暂时无法调整连接池配置,可以在事务方法里添加异常捕获与重试逻辑,比如借助Spring的@Retryable注解(需要引入spring-retry依赖):
import org.springframework.retry.annotation.Retryable; import org.springframework.transaction.CannotCreateTransactionException; @Retryable(value = CannotCreateTransactionException.class, maxAttempts = 2) @Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true, isolation = Isolation.READ_UNCOMMITTED, transactionManager = AppConstants.CHILD_TRANSACTION_MANAGER) public Map<String, Object> getParentIdFromChildsId(String childIds, int userId, int projectID) { // 你的业务代码逻辑 }
这个方案会在第一次遇到连接失效异常时自动重试一次,此时连接池会重新获取有效连接。
额外建议
你的Spring Boot版本是1.5.6,该版本已停止官方维护很久,建议尽量升级到Spring Boot 2.x的长期支持版(比如2.7.x),新版本的连接池管理和事务机制有更好的容错能力,能从根源减少这类问题的发生。
内容的提问来源于stack exchange,提问作者Bhailu
相关产品推荐
相关产品推荐

