SQL Developer调试PL/SQL执行DBMS_SCHEDULER.run_job报ORA-30687
ORA-30687 调试时触发DBMS_SCHEDULER.RUN_JOB退出问题成因分析
核心调试机制的基础冲突
- SQL Developer的PL/SQL调试器完全依赖当前调试会话的私有连接通道工作,通过在目标会话上注册调试回调钩子,实现断点感知、单步跟踪、变量状态读取的能力,整个调试链路要求当前PL/SQL执行会话不能出现上下文重置、会话重建的情况,否则调试钩子会直接失效断连。
- 该异常的本质是:当执行
DBMS_SCHEDULER.RUN_JOB()语句时,Oracle 19c的调度器模块会触发会话上下文的隔离规则,主动剥离当前PL/SQL会话上注册的调试回调钩子,最终抛出ORA-30687: session terminated by debugger错误。因为调度作业的执行权限已经被移交到独立的job slave后台进程,所以作业本身会独立运行完成,不会受调试器断连的影响。
结合当前配置的具体触发诱因
- 本次配置的作业为
JOB_TYPE => 'EXECUTABLE'类型,对应调用服务器本地cmd.exe拉起外部Java应用,这类外部作业的执行逻辑和内部PL/SQL作业存在本质区别:- 如果是存储过程类型的内部作业,即使通过
RUN_JOB同步调用,也仅会在当前会话的内存空间内跳转执行对应PL/SQL块,不会触发会话的资源隔离,调试钩子可以正常保留 - 外部可执行作业必须由独立的job slave进程承载系统命令的调用,为了避免外部进程的执行状态污染原PL/SQL会话,Oracle会在job slave拉起外部命令的阶段,强制清理原会话上挂载的所有调试回调标记,直接断开调试连接
- 如果是存储过程类型的内部作业,即使通过
- 版本适配存在已知缺陷:运行在Ubuntu 18.04上的SQL Developer 20.4.0.379版本,针对Windows Server 2016主机上部署的Oracle 19c 19.0.0.0.0外部作业调试场景没有做兼容适配,在检测到会话要移交job slave进程时,没有做调试通道的平滑迁移逻辑,直接被动触发断连。
常见认知误区澄清
- 该问题并非因为
RUN_JOB是异步调用导致会话超时:即使将RUN_JOB的USE_CURRENT_SESSION参数显式设置为TRUE,只要是外部可执行类型的作业,job slave进程接管外部命令执行的环节,必然会和原调试会话做资源隔离,不存在调试钩子保留的可能。 - 普通PL/SQL代码单步功能正常,是因为普通代码执行全程都在原会话的内存上下文内运行,不会触发会话上下文剥离的规则,和外部作业的执行链路无共性问题。
可落地的调试规避方案
- 调试过程中遇到需要执行外部调度作业的逻辑时,不要直接单步走到
RUN_JOB()语句,而是在该语句位置设置断点,调试完所有前置的作业参数配置、变量赋值逻辑后,切到普通SQL工作表手动执行RUN_JOB语句,不再依赖调试会话跟踪这一步的执行流程。 - 如果必须跟踪
RUN_JOB之后的业务逻辑,可以先手动触发作业执行完成,再回到调试链路单步验证后续代码的运行状态,避免调试会话进入外部作业的隔离触发流程。
内容的提问来源于stack exchange,提问作者Falco Preiseni
相关产品推荐
相关产品推荐

