必须使用dbms_scheduler,因dbms_job在12c/19c/21c中已废弃;最简每日定时作业需三要素:唯一job_name、明确job_type与job_action、合法repeat_interval;漏enabled=>true或日历语法错误将致作业disabled且next_run_date为null。

必须用 DBMS_SCHEDULER,DBMS_JOB 在 12c/19c/21c 中已废弃,新建项目硬切 DBMS_SCHEDULER 是唯一可行路径。
最简每日定时作业怎么写
三要素缺一不可:唯一 job_name、明确的 job_type 和 job_action、合法的 repeat_interval。漏掉 enabled => TRUE 或写错日历语法,作业就卡在 DISABLED 状态,NEXT_RUN_DATE 永远为 NULL。
-
job_name必须全局唯一(同 schema 下),建议带业务前缀,如'JOB_DATA_SYNC_DAILY' -
job_type选'STORED_PROCEDURE'(无参)或'PLSQL_BLOCK'(需完整BEGIN/END) -
job_action若为STORED_PROCEDURE,值只能是过程名,如'PROC_SYNC_ORDERS',不能带括号、参数或分号 -
repeat_interval必须大写、无多余空格,例如:'FREQ=DAILY; BYHOUR=0; BYMINUTE=0; BYSECOND=0'(凌晨零点) -
start_date是首次执行时间,不是创建时间;设成过去时间会立刻触发一次,再按规则走下一轮
存储过程带参数怎么办
DBMS_SCHEDULER 的 STORED_PROCEDURE 类型不支持传参,硬写 'MY_PROC(''20260901'')' 会直接报 ORA-27469。只有两条路可走,选哪条取决于参数是否需要每次动态计算。
- 用
PLSQL_BLOCK:把调用包进匿名块,例如'BEGIN PROC_SYNC_ORDERS(''20260901'', ''20260915''); END;'—— 但注意:字符串里写死的日期不会变,TO_CHAR(SYSDATE, ''YYYYMMDD'')这类表达式必须放在块内,且每次运行实时求值,不能提前拼成常量 - 用
PROGRAM + ARGUMENT路线:先CREATE_PROGRAM,再DEFINE_PROGRAM_ARGUMENT,最后CREATE_JOB绑定。适合需要每次运行自动算出上月起止日这类场景,但步骤多、易漏ENABLE
repeat_interval 写错会怎样
这个字段不是普通字符串,是 Oracle 内部解析的 iCalendar 表达式,容错率极低。大小写、空格、分号、时区都敏感,错一处就报 ORA-27450: invalid calendar string,作业创建失败。
- 常见错误:
'freq=daily'(小写)、'FREQ=DAILY ;BYHOUR=0'(分号前有空格)、'FREQ=DAILY; INTERVAL=1'(INTERVAL不是标准关键字) - 正确写法只认标准关键词:
FREQ、BYHOUR、BYMINUTE、BYSECOND、BYMONTHDAY、BYDAY等,全部大写,等号后无空格,分号后无空格 - 调试建议:用
DBMS_SCHEDULER.EVALUATE_CALENDAR_STRING预验证,避免上线后才发现失效
为什么 job 创建后没反应
最常见原因是没显式启用。Oracle 不会默认帮你开开关,enabled => TRUE 是必填项,不是可选项。另外两个隐蔽坑是:作业名重复导致 ORA-27477,以及权限不足导致后台进程根本看不到 job。
- 检查状态:
SELECT job_name, state, next_run_date FROM dba_scheduler_jobs WHERE job_name = 'YOUR_JOB_NAME';—— 如果state是DISABLED,就是没启用 - 检查日志:
SELECT * FROM dba_scheduler_job_log WHERE job_name = 'YOUR_JOB_NAME' ORDER BY log_date DESC;,看有没有ERROR记录 - 确认用户有
CREATE JOB权限,且目标存储过程在 job 所属 schema 下可执行(跨 schema 需显式授权)
真正难的不是写对第一行,而是让 job 在未来三个月、跨数据库升级、换时区、加参数后还能稳稳跑下去——iCalendar 表达式和参数传递路径一旦选错,后期改起来比重写还麻烦。











