如何配置DBMS_JOB于周一06:00启动并每小时运行?代码异常排查
解决DBMS_JOB周一06:00开始每小时运行的问题
首先得给你分析下现有代码的问题:你当前用的间隔表达式next_day(SYSDATE,'MONDAY')+1/24,next_day(SYSDATE,'MONDAY')会返回下周一的00:00点,加上1/24(也就是1小时)后就变成了周一01:00,而且这个表达式每次计算的都是下周一01:00,所以你的job每周只会在周一01:00跑一次,完全达不到你要的“每小时运行”的效果。
接下来分两种常见场景给你解决方案:
场景1:仅在每周一当天,从06:00开始每小时运行一次(比如6:00、7:00...23:00各执行一次)
这种需求下,我们需要让job在周一当天每小时跑一次,非周一的时候直接跳转到下周一的06:00。
方法1:创建新的DBMS_JOB
DECLARE v_job_num NUMBER; BEGIN -- 创建job,指定第一次运行时间为下周一06:00,间隔表达式实现周一每小时跑、非周一跳转到下周一06:00 SYS.DBMS_JOB.SUBMIT( job => v_job_num, what => '你的存储过程或SQL语句;', -- 替换成你实际要执行的任务 next_date => NEXT_DAY(TRUNC(SYSDATE), 'MONDAY') + 6/24, -- 下周一06:00第一次运行 interval => 'CASE WHEN TO_CHAR(SYSDATE, ''DY'', ''NLS_DATE_LANGUAGE=AMERICAN'') = ''MON'' THEN SYSDATE + 1/24 ELSE NEXT_DAY(TRUNC(SYSDATE), ''MONDAY'') + 6/24 END' ); COMMIT; DBMS_OUTPUT.PUT_LINE('创建的Job编号:' || v_job_num); END; /
方法2:修改现有Job(你的Job编号是1102745)
DECLARE v_job_num NUMBER := 1102745; BEGIN -- 先修改第一次运行时间为下周一06:00(如果当前next_date不是的话建议加上) SYS.DBMS_JOB.NEXT_DATE(v_job_num, NEXT_DAY(TRUNC(SYSDATE), 'MONDAY') + 6/24); -- 修改间隔表达式 SYS.DBMS_JOB.INTERVAL( v_job_num, 'CASE WHEN TO_CHAR(SYSDATE, ''DY'', ''NLS_DATE_LANGUAGE=AMERICAN'') = ''MON'' THEN SYSDATE + 1/24 ELSE NEXT_DAY(TRUNC(SYSDATE), ''MONDAY'') + 6/24 END' ); COMMIT; END; /
这里的CASE逻辑很直观:
- 如果当前时间是周一(显式指定
NLS_DATE_LANGUAGE=AMERICAN是为了避免数据库语言环境不同导致的判断错误),则下一次运行时间是当前时间加1小时; - 如果不是周一,则直接跳转到下周一的06:00。
场景2:周一06:00第一次运行,之后无论周几都每小时运行一次
如果你的需求是从周一06:00开始,之后不管是不是周一都每小时跑一次,那设置就简单多了:
创建新Job
DECLARE v_job_num NUMBER; BEGIN SYS.DBMS_JOB.SUBMIT( job => v_job_num, what => '你的存储过程或SQL语句;', next_date => NEXT_DAY(TRUNC(SYSDATE), 'MONDAY') + 6/24, -- 下周一06:00第一次跑 interval => 'SYSDATE + 1/24' -- 之后每小时运行一次 ); COMMIT; DBMS_OUTPUT.PUT_LINE('创建的Job编号:' || v_job_num); END; /
修改现有Job
DECLARE v_job_num NUMBER := 1102745; BEGIN SYS.DBMS_JOB.NEXT_DATE(v_job_num, NEXT_DAY(TRUNC(SYSDATE), 'MONDAY') + 6/24); SYS.DBMS_JOB.INTERVAL(v_job_num, 'SYSDATE + 1/24'); COMMIT; END; /
几个小提醒
- 测试间隔表达式:你可以用
SELECT 表达式 FROM DUAL;来验证计算结果,比如SELECT NEXT_DAY(TRUNC(SYSDATE), 'MONDAY') + 6/24 FROM DUAL;就能看到下周一06:00的具体时间; - 记得提交事务:
COMMIT一定要加,不然DBMS_JOB的修改不会生效; - 语言环境问题:如果你的数据库默认语言不是英文,直接用
DY可能返回中文“周一”之类的,所以显式指定NLS_DATE_LANGUAGE=AMERICAN更稳妥。
内容的提问来源于stack exchange,提问作者emreucar
相关产品推荐
相关产品推荐

