Spring Boot 1.5.10+JPA调用MySQL存储过程后会话未关闭致资源耗尽
解决Spring Boot JPA调用存储过程后MySQL连接不释放的问题
看你的描述,核心问题就是调用标注@Procedure的存储过程后,JDBC连接没被正确回收,最后把连接池耗干了,抛出CannotCreateTransactionException。结合Spring Boot 1.5.10这个版本的特性,还有我之前碰到过的类似问题,给你几个排查方向和解决方案:
1. 先排查存储过程本身的问题
有些存储过程内部可能藏着坑——比如没关闭的游标、残留的临时表,或者内部事务没正确提交/回滚,这会导致MySQL端的会话一直占着不放。
- 先手动在MySQL客户端跑一遍:
CALL refresh_mv_slave_holdings_for_master_fund(100);,然后用SHOW PROCESSLIST;看看调用完之后会话会不会自动消失。 - 如果手动调用也留着会话,那问题肯定在存储过程本身,得优化它的逻辑,确保所有资源都释放,事务正常结束。
2. 绕过Spring Data JPA的默认实现,手动调用存储过程
Spring Data JPA 1.5.x的@Procedure注解在某些场景下确实有连接泄漏的bug,框架默认的实现没正确释放JDBC连接。你可以试试用EntityManager手动实现调用,自己控制资源:
@Repository public class ProductRepositoryImpl implements ProductCustomRepository { @PersistenceContext private EntityManager entityManager; @Transactional public void refreshSlaveProductHoldings(Integer productId) { StoredProcedureQuery query = entityManager.createStoredProcedureQuery("refresh_mv_slave_holdings_for_master_fund"); query.registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN); query.setParameter(1, productId); try { query.execute(); } finally { // 手动清理,确保连接被回收 if (!query.isClosed()) { query.close(); } } } }
这种方式能精准控制存储过程调用的生命周期,避开框架层面的坑。
3. 调整Tomcat连接池的参数,强制回收泄漏的连接
你已经设了spring.datasource.tomcat.max-active=300,可以再加几个参数让连接池更“主动”地回收泄漏的连接:
# 连接空闲超过60秒就强制回收 spring.datasource.tomcat.remove-abandoned-timeout=60 # 启用连接回收机制 spring.datasource.tomcat.remove-abandoned=true # 记录回收日志,方便排查哪块出的问题 spring.datasource.tomcat.log-abandoned=true
这算是临时救急的办法,能缓解连接耗尽的问题,但还是得从根源解决。
4. 检查事务配置是否冲突
你说存储过程在@Transactional块里调用,得确认:
- 事务的传播行为是不是合理,别搞出嵌套事务或者事务没正常提交/回滚的情况。
- 如果存储过程内部自己开了事务,可能和Spring的事务管理冲突,导致连接被死死拿着。可以试试把
@Transactional的传播属性改成NOT_SUPPORTED,让Spring不插手存储过程的事务:
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void refreshSlaveProductHoldings(Integer productId) { // 存储过程调用逻辑 }
5. 考虑升级Spring Boot版本(如果可行的话)
Spring Boot 1.5.x早就停止维护了,后续的2.x版本修复了一大堆JPA和连接池相关的bug。如果项目允许升级,直接升到稳定的2.x版本,大概率能从根上解决这个连接泄漏的问题。
内容的提问来源于stack exchange,提问作者Kai
相关产品推荐
相关产品推荐

