DBMS_JOB已过时,必须用DBMS_SCHEDULER替代;其作业需显式COMMIT才生效,SYSDATE不保证立即执行,且无法传递事务上下文,易导致丢失、不可查、不一致等问题。
dbms_job 已过时,且无法满足真正的异步响应需求;优先用 dbms_scheduler 替代,否则容易掉进作业丢失、状态不可查、事务不一致的坑里。
DBMS_JOB.SUBMIT 后为什么作业没执行?
最常见原因是漏掉 COMMIT。DBMS_JOB.SUBMIT 只把作业注册进数据字典(USER_JOBS),但不提交事务,CJQ 进程根本看不到它。
- 必须在
END;后显式执行COMMIT;,否则作业不会入队 -
what参数必须是完整可执行语句字符串,末尾带分号,例如'my_proc();',不能传变量或拼接未转义的引号 -
next_date => SYSDATE不等于“立刻执行”,CJQ 默认每 60 秒扫描一次,延迟不可控 - Oracle 10g 及以后版本中,
DBMS_JOB已被官方标记为“deprecated”,新项目禁止使用
DBMS_SCHEDULER 提交任务后如何确保调用方拿到作业名?
关键在于用命名作业(named job)替代匿名作业,并在提交前生成唯一标识,避免依赖输出参数。
- 不要依赖
job_name => NULL让系统自动生成名字——它不可预测,也无法反向关联调用上下文 - 显式指定
job_name,例如'ASYNC_' || TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS') || '_' || v_request_id - 把该
job_name作为返回值或写入日志表,供后续查询或取消使用 - 务必设置
auto_drop => TRUE,否则作业执行完仍留在DBA_SCHEDULER_JOBS中,长期积累导致元数据膨胀
为什么不能在异步作业里直接读写调用方的事务数据?
因为 DBMS_JOB 和 DBMS_SCHEDULER 的作业都在独立会话中运行,与原始事务完全隔离。
- 作业中对表的 DML 操作属于新事务,无法看到调用方未提交的变更
- 若强行用
AUTONOMOUS_TRANSACTION绕过,会导致事务割裂:主流程回滚,作业已提交,数据不一致 - 正确做法是:把必要参数(如 ID、配置项)以字符串形式传入
what或作为job_args,让作业基于已持久化的数据工作 - 需要状态反馈时,别依赖管道(
DBMS_PIPE)——它无超时、易阻塞、不支持跨实例,改用状态表 + 轮询或数据库通知(DBMS_ALERT)
真正难的不是提交一个异步任务,而是让整个链路可追踪、可取消、可重试。命名作业、显式日志、分离上下文、禁用 DBMS_JOB,这四点漏掉任何一条,都会在压测或上线后暴露出来。


















