DBMS_SCHEDULER创建外部作业必须指定job_type => 'EXECUTABLE',使用绝对路径脚本、Oracle OS用户权限、SELinux适配、显式解释器、命令行传参及重定向日志。
DBMS_SCHEDULER 创建外部作业必须用 EXECUTABLE 类型
oracle 默认不允许可执行文件直接被 pl/sql 调用,dbms_scheduler.create_job 必须显式指定 job_type => 'executable',否则会报 ora-27369: job of type executable failed 或静默失败。这个类型决定了 oracle 用操作系统用户(不是数据库用户)去拉起进程。
常见错误是误设为 'PLSQL_BLOCK' 或 'SCRIPT'(后者只在 12cR2+ 支持且仅限 SQL*Plus 环境),结果脚本根本没运行。
-
job_type只能是'EXECUTABLE',不能是'PROGRAM'(那是封装用的中间对象) - 脚本路径必须是绝对路径,且 Oracle OS 用户(如
oracle)有执行权限和PATH中能 resolve 的依赖 - 不能用
~或环境变量(如$HOME),Oracle 不展开 shell 变量
外部脚本权限和 SELinux 是最常卡住的地方
即使 chmod +x /path/to/script.sh 也未必够——Oracle 后台进程受 SELinux 约束,默认禁止 execmem 和跨域执行。现象是作业状态变成 FAILED,日志里只有 ORA-27369: external job failed,无具体原因。
验证方式:用 Oracle OS 用户手动执行一遍脚本,再检查 ausearch -m avc -ts recent 是否有拒绝记录。
- 临时放行:
setsebool -P oracle_execmem 1(需 root) - 更稳妥的是给脚本打标签:
chcon -t bin_t /path/to/script.sh - 脚本第一行必须是
#!/bin/bash(或对应解释器),不能是#!/usr/bin/env bash(某些 Oracle 版本不识别)
如何传参、捕获输出、处理退出码
外部作业本身不返回 stdout/stderr 到数据库,只能靠重定向写文件,再用 UTL_FILE 或外部表读取。退出码($?)会映射为作业状态:0 → SUCCEEDED,非零 → FAILED。
参数传递只能靠命令行位置参数,不能用环境变量注入(Oracle 不继承 session 环境)。
- 调用时用
job_action => '/path/to/script.sh',参数写在后面:job_action => '/path/to/script.sh arg1 arg2' - 脚本内用
$1 $2接收,别指望$ORACLE_HOME这类变量自动存在 - 想看输出?在脚本末尾加
echo "done" >> /tmp/job_$(date +%s).log 2>&1,然后手动查文件 - 避免脚本后台化(如结尾加
&),否则 Oracle 认为立即退出,状态不可控
DBMS_SCHEDULER 外部作业无法调试,日志极简
Oracle 只记录作业启动时间、结束时间、状态和退出码,不存 stderr/stdout。出问题时唯一线索是 dba_scheduler_job_log 表里的 additional_info 字段,内容通常是空或只有“External job returned status: 1”。
没有类似 cron 的 /var/log/cron 级别日志,也不能 attach strace 到 Oracle 进程(会破坏稳定性)。
- 务必在脚本开头加
set -x并重定向到文件,否则等于盲跑 - 不要依赖
sqlplus或rman命令——它们可能找不到 Oracle 环境变量,得手动. oraenv或写全路径 - 测试阶段先用
run_job同步执行:DBMS_SCHEDULER.RUN_JOB('MY_JOB', use_current_session => true),方便观察阻塞点
真正麻烦的从来不是语法,而是 Oracle 进程在哪个用户、哪个安全上下文、哪套环境变量里跑你的脚本——这些细节不亲手试三次,文档里根本找不到答案。










