PL/SQL 无法捕获连接中断错误,因为 ORA-03114、ORA-03113 发生在 SQL*Net 网络层,语句未送达数据库或响应丢失,PL/SQL 引擎已失上下文,不进入 EXCEPTION 分支;重试必须由客户端或应用层实现。
PL/SQL 本身无法实现“自动重试”——连接中断、会话失效类错误根本进不了 EXCEPTION 块,重试逻辑必须由客户端或应用层控制。
ORA-03114(not connected to ORACLE)、ORA-03113(communication channel failure)等错误发生在 SQL*Net 网络层,语句甚至没发到数据库,或响应丢失,PL/SQL 引擎已失去执行上下文,直接报错退出。此时 EXCEPTION 分支完全不触发,WHEN OTHERS 形同虚设。
常见误判场景:
WHEN OTHERS THEN RAISE_APPLICATION_ERROR(-20001, 'retry later');,但连接断了根本不会执行这行DBMS_SCHEDULER 调用一个带事务的存储过程,中间网络抖动导致作业状态变成 STOPPED,但日志里看不到任何异常处理痕迹SQLCODE 能拿到 -3113 就能做判断,实际 SQLCODE 在连接中断时根本不可用(变量未初始化或返回 0)重试动作必须落在调用 PL/SQL 的外部环节,且需区分场景:
until sqlplus user/pass@db @job.sql; do sleep 10; done,配合 EXIT WHEN SQLCODE != 0; 在脚本末尾显式退出SQLException,检查 getErrorCode() 是否为 3113/3114,手动重建 Connection 并重试逻辑(注意:Oracle JDBC 驱动默认不支持 auto-reconnect,autoReconnect=true 参数无效)MAX_FAILURES 和 RESTARTABLE 属性,再结合 DBMS_SCHEDULER.ADD_EVENT_RULE 监听 job_failed 事件,触发另一个作业做补偿虽然不能让单个作业内部循环重试,但可以组合调度能力逼近效果:
max_failures => 3、restartable => TRUE
DBMS_SCHEDULER.ADD_EVENT_RULE 监听 'oracle.scheduler.job_failed',条件是 event_type = 'JOB_FAILED' 且 job_name = 'MY_MAIN_JOB'
DBMS_LOCK.SLEEP(5)),再调用同一存储过程;可限制最多触发 2 次,避免无限循环示例关键参数:job_action => 'BEGIN my_proc; END;',不是 my_proc(后者不支持参数,且无法捕获执行结果)
很多人花时间在 PL/SQL 里加 IF SQLCODE IN (-3113, -3114) THEN ...,却忘了——这个判断只在错误“被抛出并进入 EXCEPTION”时才有效;而连接中断时,SQLCODE 根本没机会被赋值,整块代码已被跳过。真正的防线不在存储过程体里,而在连接保活(如 SQL Developer 的 Keep Alive)、客户端超时设置、连接池 validation-query 配置,以及作业失败后的事件驱动补偿链路上。