SpringBoot调用Oracle存储过程:存储过程执行完毕但executeUpdate未结束
我们使用SpringBoot 3.x搭配Java 21,通过Hibernate调用Oracle数据库中的PL/SQL存储过程,该过程完整执行需10-12分钟。目前数据库表中已通过TRACE_PR日志确认存储过程已执行完毕,但Java代码中的storedProcedure.executeUpdate()方法仍在执行,始终不结束。
相关代码片段
Java代码
/** The entity manager. */ @PersistenceContext EntityManager entityManager; @jakarta.transaction.Transactional public void callStoredProcedure(String procdurename, Integer jobId) { StoredProcedureQuery storedProcedure = entityManager.createStoredProcedureQuery(procdurename) .registerStoredProcedureParameter(0, Integer.class, ParameterMode.IN); storedProcedure.setParameter(0, jobId); try { LOGGER.info("Execute Update....... "); storedProcedure.executeUpdate(); LOGGER.info("Execute Update.......End "); } finally { storedProcedure.unwrap(ProcedureOutputs.class).release(); } }
PL/SQL存储过程
PROCEDURE stored_Procedure_db(i_job_id in NUMBER) IS L_PROC_NAME VARCHAR2(100) := C_MODULE_NAME || '.stored_Procedure_db'; L_TRCSTRING VARCHAR2(1024); l_Step_Name VARCHAR2(20) := 'Test'; BEGIN TRACE_PA.TRACE_PR(L_PROC_NAME, 20, 'Start:' || i_Job_Id, 1); tr_objects_pr_primary(i_job_id); tr_objects_pr_secondary(i_job_id); TRACE_PA.TRACE_PR(L_PROC_NAME, 20, 'Ende:' || i_Job_Id); EXCEPTION WHEN OTHERS THEN begin L_TRCSTRING := 'unhandled exception ' || SQLERRM; RAISE_APPLICATION_ERROR(-20068, L_TRCSTRING); end; END stored_Procedure_db;
可能的原因及排查建议
1. Spring事务机制阻塞
方法上的@jakarta.transaction.Transactional注解会让Spring在方法结束时自动提交事务。如果存储过程执行完毕后,数据库端存在未释放的锁、事务未完成的隐式操作,Spring会一直等待事务提交完成。
排查建议:
- 临时去掉
@Transactional注解,直接调用存储过程,观察是否能正常返回。如果恢复正常,说明是事务管理导致的阻塞,可考虑在存储过程内部自行控制事务(比如添加COMMIT;),或者调整Spring事务的传播属性。
2. 隐式结果集未读取/关闭
即使存储过程只定义了IN参数,若子过程tr_objects_pr_primary或tr_objects_pr_secondary中执行了未处理的SELECT语句、未关闭的游标,Oracle会将结果集返回给客户端。Hibernate的StoredProcedureQuery会一直等待读取所有结果集才会返回。
排查建议:
- 检查存储过程及子过程的代码,确保所有游标都显式关闭,所有SELECT语句都有对应的处理(比如用
INTO子句接收结果); - 在存储过程末尾添加
COMMIT;(如果业务允许),强制结束事务并释放资源。
3. 数据库会话状态异常
存储过程日志显示结束,但数据库会话可能仍在执行后台操作(比如大事务的日志写入、索引维护),或者处于等待状态。
排查建议:
- 执行Oracle查询查看会话状态:
SELECT sid, serial#, status, wait_class, event FROM v$session WHERE program LIKE '%你的应用标识%' AND username = '数据库用户名';- 如果会话状态为
INACTIVE但Java端仍等待,说明驱动未正确接收结束信号; - 如果状态为
WAITING,查看event字段确认等待事件(比如锁等待、IO等待),针对性解决。
- 如果会话状态为
4. Oracle驱动版本兼容问题
使用的ojdbc版本与SpringBoot 3.x、Java 21不兼容,可能导致驱动在处理长耗时存储过程时出现阻塞,无法正确接收存储过程完成的信号。
排查建议:
- 升级至适配Java 21和SpringBoot 3.x的最新ojdbc版本(推荐ojdbc11的最新稳定版),确保驱动与JDK、框架版本匹配。
5. 连接池或网络超时设置不匹配
数据库连接池(如HikariCP)的超时设置过长,或者网络层面(防火墙、TCP)存在超时,可能导致连接假死,Java端误以为存储过程仍在执行。
排查建议:
- 调整连接池参数:比如HikariCP的
connectionTimeout设置为合理值(大于存储过程执行时间),maxLifetime避免长连接老化; - 检查网络防火墙是否有长连接超时限制,确保允许存储过程执行时长的连接存活。
内容的提问来源于stack exchange,提问作者Naveen Neelayyagari

