在前面學習了存儲過程的開發、調試之后,我們現在就需要來使用存儲過程了。簡單的使用,像上篇《懵懂oracle之存儲過程2》中提到的存儲過程調用,我們可以將寫好的存儲過程在另一個PL/SQL塊亦或是另一個存儲過程中調用執行,而很多情況下,我們往往需要定時執行這個存儲過程,那么我們就需要使用到Oracle的JOB,讓我們的數據庫可以定期的執行特定的任務。
下面就讓我們來了解下JOB的方方面面:
在Oracle 10g以前,Oracle提供了dbms_job系統包來實現job,到Oracle 10g時,就多出了dbms_scheduler包來實現job,它比dbms_job擁有更強大的功能和更靈活的機制,在本文暫只介紹dbms_job的知識,所用的數據庫版本Oracle 11g。
1 初始化
1.1 初始化權限
使用dbms_job包如果遇到權限問題,那么需要使用管理員賬號給此用戶賦予權限:
1 grant execute on dbms_job to 用戶;
1.2 初始化參數
重點關注job_queue_processes參數,它告訴了數據庫最多可創建多少個job進程來運行job,可通過下面語句查詢改參數值情況:
1 select name, value, display_value from v$parameter where name in ('spfile', 'job_queue_processes');
當job_queue_processes參數對應的value為0時,則代表所有創建的job都不會運行,因此我們需將此參數值根據各自需要修改至n(1~1000):
- 當上述語句未查詢出spfile參數時,則表示數據庫以pfile啟動,該文件默認位置為%ORACLE_HOME%\database目錄下的init<sid>.ora文件(sid-->數據庫實例名)。此時若要修改參數值,則需打開此文件進行增加或修改下行信息,而后重啟數據庫才能生效:
1 JOB_QUEUE_PROCESSES=n
-
當上述語句可查詢出spfile參數時,則表示數據庫以spfile啟動,該文件的位置可從value值中得到。此時若要修改參數值,則可通過在數據庫執行下列語句進行修改:
1 alter system set job_queue_processes=n; 2 /* 3 alter system 參數名=值 [scope=應用范圍]; 4 scope需知: 5 scope=both,表示修改會立即生效且會修改spfile文件以確保數據庫在重啟后也會生效如果(以spfile啟動此項為缺省值); 6 scope=memory,表示修改會立即生效但不會修改spfile文件,因此重啟后失效(以pfile啟動此項為缺省值,且只可設置這個值); 7 scope=spfile,表示只修改spfile文件,在重啟數據庫后才生效(對應靜態參數則只可設置此項值,設置其它值會報錯: 8 ORA-02095: specified initialization parameter cannot be modified)。 9 */
2 dbms_job包分析(可在數據庫中查看此包獲取相關信息,暫未分析包內user_export存過的用法)
2.1 內部存過參數匯總
2.2 內部存過詳解

1 create or replace procedure sp_test_hll_170726 AUTHID CURRENT_USER as 2 v_flag number; 3 begin 4 select count(1) 5 into v_flag 6 from user_tables 7 where table_name = 'TEST_TABLE_170726'; 8 if v_flag = 0 then 9 execute immediate 'create table test_table_170726(id number, create_time date default sysdate)'; 10 end if; 11 select count(1) 12 into v_flag 13 from user_sequences 14 where sequence_name = 'SEQ_TEST_TABLE_170726_ID'; 15 if v_flag = 0 then 16 execute immediate 'create sequence seq_test_table_170726_id'; 17 end if; 18 execute immediate 'insert into test_table_170726(id) values(seq_test_table_170726_id.nextval)'; 19 commit; 20 end sp_test_hll_170726; 21 /
1) submit:用於新建一個定時任務
- 定義:
1 procedure submit(job out binary_integer, 2 what in varchar2, 3 next_date in date default sysdate, 4 interval in varchar2 default 'null', 5 no_parse in boolean default false, 6 instance in binary_integer default 0, 7 force in boolean default false);
- 范例1:
1 declare 2 jobno number; 3 begin 4 dbms_job.submit( 5 jobno,--定義的變量作為submit存過的出參,submit內部調用序列生成此值 6 'sp_test_hll_170726;' , --job要執行的工作(范例為要執行的存儲過程,必須加分號,格式如:存過1;存過2;存過3;……) 7 sysdate,--設置下次運行時間為當前系統時間,以使job在提交后立馬運行(因為之后的系統時間>=此時的'sysdate') 8 'sysdate+10/(24*60*60)' --設置定時周期為10秒運行一次 9 ); 10 dbms_output.put_line(jobno);--輸出以供查看本次創建的job的編號,或查看dba_jobs/all_jobs/user_jobs視圖中最新行亦可 11 commit;--請記得提交,提交之后才會生效並按計划執行此項定時任務 12 end; 13 /
- 范例2(存過sp_hll_test_20170415見《懵懂oracle之存儲過程》):
1 declare 2 jobno number; 3 begin 4 dbms_job.submit(jobno, 5 'declare 6 a number; 7 b date; 8 c varchar2(20); 9 d number; 10 status user_tables.status%type; 11 e varchar2(200); 12 begin 13 sp_hll_test_20170415(a, b, c, d, status, e); 14 a := 3; 15 sp_hll_test_20170415(a, to_date(''2017-6-16'', ''yyyy-mm-dd''), ''我是常量C'', d, ''0'', e); 16 insert into test_table_170726(id,create_time) values (seq_test_table_170726_id.nextval,to_date(''2017-6-16'', ''yyyy-mm-dd'')); 17 commit; 18 end;', --job要執行的工作(范例為要執行的PL/SQL塊,塊內單引號處理成雙單引號) 19 case 20 when sysdate > trunc(sysdate) + 21 (11 * 60 * 60 + 11 * 60 + 11) / (24 * 60 * 60) then 22 trunc(sysdate + 1) + 23 (11 * 60 * 60 + 11 * 60 + 11) / (24 * 60 * 60) 24 else 25 trunc(sysdate) + (11 * 60 * 60 + 11 * 60 + 11) / (24 * 60 * 60) 26 end, --設置下次運行時間為接下來最近的一次11點11分11秒 27 null --設置為單次運行,一般用於需單次運轉的耗時較長的任務,在成功完成后job記錄會自動刪除掉 28 ); 29 dbms_output.put_line(jobno); 30 commit; 31 end; 32 /
- 備注:
1. what參數,用於定時任務執行的具體內容:
格式 ==> 存過1;存過2;存過3;…… | '處理過單引號的PL/SQL塊'
建議使用后者,如果是前者情況,也用begin end進行包裹,如 begin 存過1;存過2;存過3;…… end; ,否則少數情況下會出現一些莫名其妙的問題……暫無實例。
2. interval參數,用於設置定時任務時間間隔:
格式 ==> null | '處理過單引號的時間表達式'
設置為null表示單次運行,在成功完成后會從JOB任務隊列中刪除此JOB。
時間表達式:通過 select 時間表達式 from dual; 可得到一個未來時間點,每次任務開始執行之前都獲取這個未來時間點作為下次運行任務的時間,然后在任務執行完成后,才會把此時間更新至JOB任務隊列的next_date字段中,等待下次sysdate >= next_date時再次執行此任務。之所以“>=”而不是“=”,是因為存在后面幾種情況:
-1-創建定時任務時,next_date就小於系統時間;
-2-單次任務執行的時間超過任務開始執行時計算出的next_date,以致next_date小於任務執行完成后的系統時間,此時任務會立馬進行再一輪的執行;
-3-參數job_queue_processes的限制或者數據庫性能的限制或數據庫關閉等,導致next_date=當時的sysdate時,任務無法按時開始執行。
由於上面第三種情況的存在,因此對於interval參數設置大致可分兩種情況:
-1 時間定隔循環,不考慮時間點的精確性,則只需使用sysdate即可,例如 interval = 'sysdate + 數值' ,數值(1=1天,1/24=1小時,1/(24*60)=1分鍾,1/(24*60*60)=1秒鍾),數值為1時實現每隔一天執行一次這樣的簡單循環。
-2 時間定點循環,需確保每次執行的時間點精確性,則一般需配合trunc函數進行處理,例如 interval = 'trunc(sysdate,''dd'') + 數值' ,數值為1/24時實現每天1點執行此任務這樣精確的循環,以消除每次執行定時任務時的時間飄移的積累,以致時間點越來越不正確,同時由他人手工調用dbms_job.run對某定時任務進行手動執行,導致取手動運行任務時的系統時間作為sysdate計算下次的時間會產生更大的時間差異,也會使執行的時間和當初計划的時間不符的現象出現,因此用trunc等函數處理來保證時間點的精確性。
常用函數trunc、numtoyminterval、numtoyminterval、add_months、next_day、last_day介紹:
1 select sysdate, trunc(sysdate), trunc(sysdate,'MON') from dual; 2 /* 3 trunc(date, [format]): 4 format可取值匯總(不區分大小寫): 5 本世紀第一天 ==> CC,SCC 6 本年第一天 ==> SYYYY, YYYY, YEAR, SYEAR, YYY, YY, Y 7 本ISO年第一天(每個星期從星期一開始,每年的第一個星期包含當年的第一個星期四(並且總是包含1月4日)) ==> IYYY, IY, I 8 本季度第一天 ==> Q 9 本月第一天 ==> MONTH, MON, MM, RM 10 本周第一天 ==> WW(按年度1月1日的第一天為每周第一天), 11 IW(星期一為每周第一天), 12 W(按月份1日的第一天作為每周第一天), 13 DAY, DY, D(星期日為每周第一天) 14 本日(零點零分)(缺省值) ==> DDD, DD, J 15 本小時(零分零秒) ==> HH, HH12, HH24 16 本分鍾(零秒) ==> MI 17 */ 18 19 select sysdate + numtoyminterval(-5, 'year') 五年前, 20 sysdate + numtodsinterval(-10, 'day') 十天前, 21 sysdate + numtodsinterval(-2, 'hour') 兩小時前, 22 sysdate + numtodsinterval(1, 'minute') 一分鍾前, 23 sysdate + numtodsinterval(10, 'second') 十秒后, 24 sysdate + numtoyminterval(3, 'month') 三月后 25 from dual; 26 /* 27 numtodsinterval(num, format): 28 num可取整數(正整數表示加,負整數表示減); 29 format可取值匯總(不區分大小寫):DAY,HOUR,MINUTE,SECOND 30 31 numtoyminterval(num, format): 32 num可取整數(正整數表示加,負整數表示減); 33 format可取值匯總(不區分大小寫):YEAR,MONTH 34 */ 35 36 select sysdate 現在, add_months(sysdate, -12) 一年前, add_months(sysdate, 3) 三月后 from dual; 37 /* 38 add_months(date, num): 39 date為具體時間,經add_months處理不會變動時分秒,日期年月進行加減; 40 num可取整數(正整數表示加,負整數表示減); 41 */ 42 43 select next_day(sysdate, 44 case value 45 when 'SIMPLIFIED CHINESE' then 46 '星期六' 47 else 48 'SAT' 49 end) 下周一此時此分此秒, next_day(sysdate, 1) 下周日此時此分此秒 50 from v$parameter 51 where name = 'nls_date_language'; 52 /* 53 next_day(date, format) : 54 date為具體時間,經next_day處理不會變動時分秒,日期被處理至下個周一~周日; 55 format可取值匯總(不區分大小寫): 56 星期一~星期日(對應字符集NLS_DATE_LANGUAGE = SIMPLIFIED CHINESE) 57 Monday~Sunday 或者 Mon~Sun(對應字符集NLS_DATE_LANGUAGE = AMERICAN) 58 1~7(1為周日) 59 */ 60 61 select to_date('2017-2-1 11:11:11', 'yyyy-mm-dd hh24:mi:ss') "2017/2/1 11:11:11", 62 last_day(to_date('2017-2-1 11:11:11', 'yyyy-mm-dd hh24:mi:ss')) "17年2月末此時此分此秒" 63 from dual; 64 /* 65 last_day(date) : 66 date為具體時間,經last_day處理不會變動時分秒,日期被處理至月底最后一天 67 */
在Oracle RAC環境下,多個數據庫實例並發使用同一個數據庫,是Oracle9i新版數據庫中采用的一項新技術,解決了傳統數據庫應用中面臨的一個重要問題:高性能、高可伸縮性與低價格之間的矛盾!但是在涉及到我們的定時任務時,如果是RAC環境,它是怎么運行的呢?有多台機器這個定時任務這次到底會在哪個機器上運行呢?instance參數就可配置指定機器對應的數據庫實例,如不修改默認此值為0,表示就是所有數據庫實例都可運行此項定時任務,每次這個任務執行時就可能在a機器,也可能在b機器,一般我們也是不指定此值的。當遇到需要指定此值時,需關注下面查詢的情況,取instance_name作為instance參數值。
1 select inst_id,instance_number,instance_name,host_name, 2 utl_inaddr.get_host_address(host_name) public_ip,status,version 3 from gv$instance;
同時force參數在設置為true時,也能達到和instance=0時一樣的效果,解除JOB執行和數據庫實例的關聯性,它的默認值是false,表示按照instance值的情況進行判斷數據庫實例的關聯性。
4. what、interval參數都需注意內部單引號處理成雙單引號,可用 select 參數值 from dual; 查詢得到實際對應的存過或PL/SQL塊或時間表達式,來判斷是否設置正確。
2) isubmit:用於新建一個定時任務同時指定JOB編號
- 定義:
1 procedure isubmit(job in binary_integer, 2 what in varchar2, 3 next_date in date, 4 interval in varchar2 default 'null', 5 no_parse in boolean default false);
- 范例:
1 begin 2 dbms_job.isubmit(23, --指定job編號,不可用已有job的編號,否則報違反唯一約束的異常 3 'declare 4 a number; 5 b date; 6 c varchar2(20); 7 d number; 8 status user_tables.status%type; 9 e varchar2(200); 10 begin 11 sp_hll_test_20170415(a, b, c, d, status, e); 12 a := 3; 13 sp_hll_test_20170415(a, to_date(''2017-6-16'', ''yyyy-mm-dd''), ''我是常量C'', d, ''0'', e); 14 insert into test_table_170726(id,create_time) values (seq_test_table_170726_id.nextval,to_date(''2017-6-16'', ''yyyy-mm-dd'')); 15 commit; 16 end;', 17 sysdate, 18 'trunc(sysdate + numtoyminterval(1,''year''),''yyyy'')+1/24' --每年一月一號一點執行 19 ); 20 commit; 21 end; 22 /
- 備注:
除job為入參需指定外,其它使用情況與submit相同,指定job編號時,不可用已存在job的編號,否則導致異常 ORA-00001: 違反唯一約束條件 (SYS.I_JOB_JOB) 。
3) remove:用於從JOB任務隊列中移除一個JOB(不會中斷仍在運行的JOB)
- 定義:
1 procedure remove(job in binary_integer);
- 范例:
1 begin 2 dbms_job.remove(23); 3 commit; 4 end; 5 /
- 備注:
移除需移除已存在JOB,否則導致異常 ORA-23421: 作業編號111在作業隊列中不是一個作業 。
4) what:用於修改what參數值
- 定義:
1 procedure what(job in binary_integer, what in varchar2);
- 范例:
1 declare 2 jobno number; 3 begin 4 select job into jobno from user_jobs where what like '%sp_test_hll_170726%'; 5 dbms_job.what(jobno, 'begin sp_test_hll_170726; end;'); --修改成pl/sql塊形式 6 commit; 7 end; 8 /
5) next_date:用於修改next_date參數值
- 定義:
1 procedure next_date(job in binary_integer, next_date in date);
- 范例:
1 declare 2 jobno number; 3 begin 4 select job into jobno from user_jobs where what like '%sp_test_hll_170726%'; 5 dbms_job.next_date(jobno, trunc(sysdate + 1)); --修改最近一次待執行的時間至明天凌晨 6 commit; 7 end; 8 /
6) interval:用於修改interval參數值
- 定義:
1 procedure interval(job in binary_integer, interval in varchar2);
- 范例:
1 declare 2 jobno number; 3 begin 4 select job into jobno from user_jobs where what like '%sp_test_hll_170726%'; 5 dbms_job.interval(jobno, 'sysdate + 1'); --修改為每隔一天運行一次 6 commit; 7 end; 8 /
7) instance:用於修改instance、force參數值
- 定義:
1 procedure instance(job in binary_integer, 2 instance in binary_integer, 3 force in boolean default false);
- 范例:
1 declare 2 jobno number; 3 begin 4 select job into jobno from user_jobs where what like '%sp_test_hll_170726%'; 5 dbms_job.instance(jobno, 1); --修改為數據庫實例1才能運行此定時任務 6 commit; 7 end; 8 /
- 備注:
請勿修改已在運行的JOB的數據庫實例,根據網絡搜索得知:job會不再運行,並出現等待事件:enq: TX - row lock contention,執行的sql是 update sys.job$ set this_date=:1 where job=:2 ,也就是在更新sys的sys.job$表,最后只能殺掉此會話,才消除此等待事件。
一般情況下,建立不要指定JOB在特定實例運行,通常都默認為0。
下面change也需注意此處備注。
8) change:用於修改what、next_date、interval、instance、force參數值
- 定義:
1 procedure change(job in binary_integer, 2 what in varchar2, 3 next_date in date, 4 interval in varchar2, 5 instance in binary_integer default null, 6 force in boolean default false);
- 范例:
1 declare 2 jobno number; 3 begin 4 select job into jobno from user_jobs where what like '%sp_test_hll_170726%'; 5 dbms_job.change(jobno, 6 'begin sp_test_hll_170726; end;', 7 sysdate, 8 'sysdate + 1/24');--實現多參數修改 9 commit; 10 end; 11 /
9) broken:用於給定時任務添加或去除中斷標識,將任務掛起或取消掛起(不會中斷仍在運行的JOB)
- 定義:
1 procedure broken(job in binary_integer, 2 broken in boolean, 3 next_date in date default sysdate);
- 范例:
1 declare 2 jobno number; 3 begin 4 select job into jobno from user_jobs where what like '%sp_test_hll_170726%'; 5 dbms_job.broken(jobno, true);--掛起 6 commit; 7 end; 8 /
- 備注:
掛起時,會修改JOB任務隊列中字段broken='Y',next_date='4000/1/1',next_sec='00:00:00',只要broken='Y',就算next_date<sysdate,此任務也不會執行;
取消掛起時,會修改broken='N',next_date與next_sec安照next_date參數值進行調整,任務查詢開始按計划執行。
10) run:用於立即執行此定時任務(被broken掛起的存過也會取消掛起並運行)
- 定義:
1 procedure run(job in binary_integer, force in boolean default false);
- 范例:
1 declare 2 jobno number; 3 begin 4 select job into jobno from user_jobs where what like '%sp_test_hll_170726%'; 5 dbms_job.run(jobno);--立即運行 6 commit; 7 end; 8 /
- 備注:
當任務掛起時,會修改broken='N';
當數據庫實例不符時也可通過修改force=true以強制在當前數據庫實例運行,確保run能一定運行此項任務。
3 JOB任務隊列查詢處理匯總
3.1 表匯總(SYS.JOB$、DBA_JOBS、ALL_JOBS、USER_JOBS、DBA_JOBS_RUNNING)
在通過上面介紹的dbms_job包對JOB進行的處理,實際上處理的是數據庫的任務隊列表SYS.JOB$,我們可以通過下面語句查看該表情況:
1 select t.job, t.lowner, t.powner, t.cowner, t.last_date, t.this_date, t.next_date, t.total, t.interval#, t.failures, t.flag, t.what, 2 t.nlsenv, t.env, t.charenv, t.field1, t.scheduler_flags, t.xid 3 /*, t.cur_ses_label, t.clearance_hi, t.clearance_lo 4 不能查詢這三個字段,會報異常ORA-00932: 數據類型不一致: 應為 NUMBER, 但卻獲得 LABEL 5 它們的數據類型為MLSLABEL,在TRUSTED ORACLE中用來保存可變長度二進制標簽。 6 */ 7 from sys.job$ t;
但是它的數據長得不好看,Oracle提供了我們兩個視圖(DBA_JOBS、USER_JOBS)可以查看:

1 create or replace view sys.dba_jobs as 2 select JOB, lowner LOG_USER, powner PRIV_USER, cowner SCHEMA_USER, 3 LAST_DATE, substr(to_char(last_date,'HH24:MI:SS'),1,8) LAST_SEC, 4 THIS_DATE, substr(to_char(this_date,'HH24:MI:SS'),1,8) THIS_SEC, 5 NEXT_DATE, substr(to_char(next_date,'HH24:MI:SS'),1,8) NEXT_SEC, 6 (total+(sysdate-nvl(this_date,sysdate)))*86400 TOTAL_TIME, 7 decode(mod(FLAG,2),1,'Y',0,'N','?') BROKEN, 8 INTERVAL# interval, FAILURES, WHAT, 9 nlsenv NLS_ENV, env MISC_ENV, j.field1 INSTANCE 10 from sys.job$ j 11 where BITAND(j.scheduler_flags, 2) IS NULL OR 12 BITAND(j.scheduler_flags, 2) = 0 /* don't show jobs with drop flag */; 13 comment on table SYS.DBA_JOBS is 'All jobs in the database'; 14 comment on column SYS.DBA_JOBS.JOB is 'Identifier of job. Neither import/export nor repeated executions change it.'; 15 comment on column SYS.DBA_JOBS.LOG_USER is 'USER who was logged in when the job was submitted'; 16 comment on column SYS.DBA_JOBS.PRIV_USER is 'USER whose default privileges apply to this job'; 17 comment on column SYS.DBA_JOBS.SCHEMA_USER is 'select * from bar means select * from schema_user.bar '; 18 comment on column SYS.DBA_JOBS.LAST_DATE is 'Date that this job last successfully executed'; 19 comment on column SYS.DBA_JOBS.LAST_SEC is 'Same as LAST_DATE. This is when the last successful execution started.'; 20 comment on column SYS.DBA_JOBS.THIS_DATE is 'Date that this job started executing (usually null if not executing)'; 21 comment on column SYS.DBA_JOBS.THIS_SEC is 'Same as THIS_DATE. This is when the last successful execution started.'; 22 comment on column SYS.DBA_JOBS.NEXT_DATE is 'Date that this job will next be executed'; 23 comment on column SYS.DBA_JOBS.NEXT_SEC is 'Same as NEXT_DATE. The job becomes due for execution at this time.'; 24 comment on column SYS.DBA_JOBS.TOTAL_TIME is 'Total wallclock time spent by the system on this job, in seconds'; 25 comment on column SYS.DBA_JOBS.BROKEN is 'If Y, no attempt is being made to run this job. See dbms_jobq.broken(job).'; 26 comment on column SYS.DBA_JOBS.INTERVAL is 'A date function, evaluated at the start of execution, becomes next NEXT_DATE'; 27 comment on column SYS.DBA_JOBS.FAILURES is 'How many times has this job started and failed since its last success?'; 28 comment on column SYS.DBA_JOBS.WHAT is 'Body of the anonymous PL/SQL block that this job executes'; 29 comment on column SYS.DBA_JOBS.NLS_ENV is 'alter session parameters describing the NLS environment of the job'; 30 comment on column SYS.DBA_JOBS.MISC_ENV is 'a versioned raw maintained by the kernel, for other session parameters'; 31 comment on column SYS.DBA_JOBS.INSTANCE is 'Instance number restricted to run the job';

1 create or replace view sys.user_jobs as 2 select j."JOB",j."LOG_USER",j."PRIV_USER",j."SCHEMA_USER",j."LAST_DATE",j."LAST_SEC",j."THIS_DATE",j."THIS_SEC",j."NEXT_DATE",j."NEXT_SEC",j."TOTAL_TIME",j."BROKEN",j."INTERVAL",j."FAILURES",j."WHAT",j."NLS_ENV",j."MISC_ENV",j."INSTANCE" from dba_jobs j, sys.user$ u where 3 j.priv_user = u.name 4 and u.user# = USERENV('SCHEMAID'); 5 comment on table SYS.USER_JOBS is 'All jobs owned by this user'; 6 comment on column SYS.USER_JOBS.JOB is 'Identifier of job. Neither import/export nor repeated executions change it.'; 7 comment on column SYS.USER_JOBS.LOG_USER is 'USER who was logged in when the job was submitted'; 8 comment on column SYS.USER_JOBS.PRIV_USER is 'USER whose default privileges apply to this job'; 9 comment on column SYS.USER_JOBS.SCHEMA_USER is 'select * from bar means select * from schema_user.bar '; 10 comment on column SYS.USER_JOBS.LAST_DATE is 'Date that this job last successfully executed'; 11 comment on column SYS.USER_JOBS.LAST_SEC is 'Same as LAST_DATE. This is when the last successful execution started.'; 12 comment on column SYS.USER_JOBS.THIS_DATE is 'Date that this job started executing (usually null if not executing)'; 13 comment on column SYS.USER_JOBS.THIS_SEC is 'Same as THIS_DATE. This is when the last successful execution started.'; 14 comment on column SYS.USER_JOBS.NEXT_DATE is 'Date that this job will next be executed'; 15 comment on column SYS.USER_JOBS.NEXT_SEC is 'Same as NEXT_DATE. The job becomes due for execution at this time.'; 16 comment on column SYS.USER_JOBS.TOTAL_TIME is 'Total wallclock time spent by the system on this job, in seconds'; 17 comment on column SYS.USER_JOBS.BROKEN is 'If Y, no attempt is being made to run this job. See dbms_jobq.broken(job).'; 18 comment on column SYS.USER_JOBS.INTERVAL is 'A date function, evaluated at the start of execution, becomes next NEXT_DATE'; 19 comment on column SYS.USER_JOBS.FAILURES is 'How many times has this job started and failed since its last success?'; 20 comment on column SYS.USER_JOBS.WHAT is 'Body of the anonymous PL/SQL block that this job executes'; 21 comment on column SYS.USER_JOBS.NLS_ENV is 'alter session parameters describing the NLS environment of the job'; 22 comment on column SYS.USER_JOBS.MISC_ENV is 'a versioned raw maintained by the kernel, for other session parameters'; 23 comment on column SYS.USER_JOBS.INSTANCE is 'Instance number restricted to run the job';
同時通過下面語句我們可以知道,還有一個同義詞ALL_JOBS:

1 select * 2 from all_objects t 3 where t.object_name in ('DBA_JOBS', 'ALL_JOBS', 'USER_JOBS'); 4 select * 5 from sys.all_synonyms 6 where synonym_name in ('DBA_JOBS', 'ALL_JOBS', 'USER_JOBS');
我們通過下面語句都能查詢我們建立好的JOB的信息:
1 select * from dba_jobs; 2 select * from all_jobs; 3 select * from user_jobs;
DBA_JOBS/ALL_JOBS/USER_JOBS各字段的含義如下:
1 字段(列) 數據類型 描述 2 JOB NUMBER 任務的唯一標示號 3 【Identifier of job. Neither import/export nor repeated executions change it.】 4 LOG_USER VARCHAR2(30) 提交任務時登錄的用戶 5 【USER who was logged in when the job was submitted】 6 PRIV_USER VARCHAR2(30) 任務默認權限對應的用戶 7 【USER whose default privileges apply to this job】 8 SCHEMA_USER VARCHAR2(30) 對任務作語法分析的用戶模式(查詢bar表代表查詢schema_user.bar表) 9 【select * from bar means select * from schema_user.bar】 10 LAST_DATE DATE 最后一次成功運行任務的時間 11 【Date that this job last successfully executed】 12 LAST_SEC VARCHAR2(32) 長度為8的HH24:MI:SS格式的LAST_DATE 13 【Same as LAST_DATE. This is when the last successful execution started.】 14 THIS_DATE DATE 正在運行任務的開始時間,如果沒有運行任務則為null 15 【Date that this job started executing (usually null if not executing)】 16 THIS_SEC VARCHAR2(32) 長度為8的HH24:MI:SS格式的THIS_DATE 17 【Same as THIS_DATE. This is when the last successful execution started.】 18 NEXT_DATE DATE 下一次定時運行任務的時間 19 【Date that this job will next be executed】 20 NEXT_SEC VARCHAR2(32) 長度為8的HH24:MI:SS格式的NEXT_DATE 21 【Same as NEXT_DATE. The job becomes due for execution at this time.】 22 TOTAL_TIME NUMBER 數據庫用於執行此任務的總秒數統計 23 【Total wallclock time spent by the system on this job, in seconds】 24 BROKEN VARCHAR2(1) 中斷標識,Y表示任務中斷,不再嘗試執行此任務 25 【If Y,no attempt is being made to run this job. See dbms_jobq.broken(job).】 26 INTERVAL VARCHAR2(200) 用於計算下此運行時間的時間表達式 27 【A date function, evaluated at the start of execution, becomes next NEXT_DATE】 28 FAILURES NUMBER 自最后一次成功之后任務運行失敗的總次數 29 【How many times has this job started and failed since its last success?】 30 WHAT VARCHAR2(4000) 任務執行的匿名PL/SQL塊 31 【Body of the anonymous PL/SQL block that this job executes】 32 NLS_ENV VARCHAR2(4000) 任務運行的NLS會話設置 33 【alter session parameters describing the NLS environment of the job】 34 MISC_ENV RAW(32) 任務運行的其他一些會話參數 35 【a versioned raw maintained by the kernel, for other session parameters】 36 INSTANCE NUMBER 任務執行時限制關聯的數據庫實例 37 【Instance number restricted to run the job】
同時,Oracle還提供了DBA_JOBS_RUNNING視圖供我們查詢正在運行的任務:

1 create or replace view sys.dba_jobs_running as 2 select v.SID, v.id2 JOB, j.FAILURES, 3 LAST_DATE, substr(to_char(last_date,'HH24:MI:SS'),1,8) LAST_SEC, 4 THIS_DATE, substr(to_char(this_date,'HH24:MI:SS'),1,8) THIS_SEC, 5 j.field1 INSTANCE 6 from sys.job$ j, v$lock v 7 where v.type = 'JQ' and j.job (+)= v.id2; 8 comment on table SYS.DBA_JOBS_RUNNING is 'All jobs in the database which are currently running, join v$lock and job$'; 9 comment on column SYS.DBA_JOBS_RUNNING.SID is 'Identifier of process which is executing the job. See v$lock.'; 10 comment on column SYS.DBA_JOBS_RUNNING.JOB is 'Identifier of job. This job is currently executing.'; 11 comment on column SYS.DBA_JOBS_RUNNING.FAILURES is 'How many times has this job started and failed since its last success?'; 12 comment on column SYS.DBA_JOBS_RUNNING.LAST_DATE is 'Date that this job last successfully executed'; 13 comment on column SYS.DBA_JOBS_RUNNING.LAST_SEC is 'Same as LAST_DATE. This is when the last successful execution started.'; 14 comment on column SYS.DBA_JOBS_RUNNING.THIS_DATE is 'Date that this job started executing (usually null if not executing)'; 15 comment on column SYS.DBA_JOBS_RUNNING.THIS_SEC is 'Same as THIS_DATE. This is when the last successful execution started.'; 16 comment on column SYS.DBA_JOBS_RUNNING.INSTANCE is 'The instance number restricted to run the job';
通過下面語句可簡單查詢該表情況:
1 select * from dba_jobs_running;
DBA_JOBS_RUNNING各字段含義如下:
1 字段(列) 數據類型 描述 2 SID NUMBER 正在運行任務的會話ID 3 【Identifier of process which is executing the job. See v$lock. 】 4 JOB NUMBER 正在運行任務的唯一標示號 5 【Identifier of job. This job is currently executing.】 6 FAILURES NUMBER 自最后一次成功之后任務運行失敗的總次數 7 【How many times has this job started and failed since its last success?】 8 LAST_DATE DATE 最后一次成功運行任務的時間 9 【Date that this job last successfully executed】 10 LAST_SEC VARCHAR2(32) 長度為8的HH24:MI:SS格式的LAST_DATE 11 【Same as LAST_DATE. This is when the last successful execution started.】 12 THIS_DATE DATE 正在運行任務的開始時間,如果沒有運行任務則為null 13 【Date that this job started executing (usually null if not executing)】 14 THIS_SEC VARCHAR2(32) 長度為8的HH24:MI:SS格式的THIS_DATE 15 【Same as THIS_DATE. This is when the last successful execution started.】 16 INSTANCE NUMBER 任務執行時限制關聯的數據庫實例 17 【Instance number restricted to run the job
3.2 JOB的失敗重試
當JOB實現失敗時,數據庫會自動安排重新執行,此時JOB執行時間按下面情況來定:
1) 如果sysdate>=next_date,則直接執行;
2) 第i次失敗,等待2i分鍾后開始第i+1次數據庫自動安排的重新執行,當2i>1440分鍾時,時間固定為1440分鍾;
3) 重試次數達16次時,JOB不再自動執行(用戶還是可手動執行再失敗的),標記中斷標識,broken='Y',next_date='4000/1/1',next_sec='00:00:00'。
3.3 停止正在運行的JOB
由於remove、broken都只是影響任務后續的執行情況,並不會對正在運行的任務造成影響,而有些情況下,由於存儲過程的問題或者數據之間的影響等各種原因導致JOB執行異常,我們需要終止正在運行的異常JOB;也可能是JOB執行時間過長,人為需要停止正在運行的JOB。在這個時候我們需要按下面步驟進行處理:
1 /*** 第一步:查詢JOB情況得到需要停止的JOB的編號 ***/ 2 select * from user_jobs; 3 select * from dba_jobs_running; 4 5 /*** 第二步:將需要停止的JOB標記中斷,以避免停止后又運行 ***/ 6 begin 7 dbms_job.broken(job編號, true); 8 commit; 9 end; 10 / 11 12 /*** 第三步:查詢JOB運行情況,並選擇適當語句殺會話,甚至殺進程(謹慎操作) ***/ 13 select /*b.sid, -- session的id 14 c.serial#, -- session的序列號 15 d.spid, -- 操作系統進程ID*/ 16 b.job, -- JOB編號 17 a.what, -- 任務內容 18 b.failures, -- 失敗次數 19 b.this_date, -- 開始時間 20 floor(sysdate - b.this_date) || '天' || 21 to_char(trunc(sysdate, 'dd') + (sysdate - b.this_date), 'hh24:mi:ss') this_total, -- 當前耗時 22 (select f.sql_fulltext 23 from v$locked_object e, v$sql f 24 where e.session_id = c.sid 25 and f.hash_value = c.sql_hash_value 26 and rownum = 1) sql_fulltext, -- 如果鎖對象,則獲取當前sql 27 c.inst_id, -- 數據庫實例ID 28 c.status, --會話狀態 29 'alter system kill session ''' || b.sid || ',' || c.serial# || 30 ''' immediate;' 普通環境殺會話, -- session級殺會話 31 'alter system kill session ''' || b.sid || ',' || c.serial# || ',@' || 32 c.inst_id || ''' immediate;' RAC環境殺會話, -- RAC環境session級殺會話 33 /* 34 kill session語句並不實際殺死會話,只相當於讓會話自我清除,在某些情況下,例如等待遠程數據庫應答或 35 回滾當前事務時,都會等待這些操作完成,這時就將會話狀態標記為"marked for kill",數據庫會盡快將它殺掉, 36 如果加上immediate,那么則會要求將控制權立即返回給當前會話 37 */ 38 'alter system disconnect session ''' || b.sid || ',' || c.serial# || 39 ''' post_transaction或immediate;' 數據庫殺進程, 40 'alter system disconnect session ''' || b.sid || ',' || c.serial# || ',@' || 41 c.inst_id || ''' post_transaction或immediate;' 數據庫RAC環境殺進程, 42 /* 43 disconnect是在數據庫中從操作系統層面清除服務器進程, 44 post_transaction表示清除前需等待正在進行的事務完成, 45 而immediate則表示立即清除並回滾正在進行的事務, 46 兩者必須有其一,都有時,post_transaction優先級高,忽視immediate子句。 47 用disconnect我們就不用切換到操作系統層面用下面語句去清除進程了 48 */ 49 g.host_name || '==>' || utl_inaddr.get_host_address(g.host_name) "機器==>IP", -- 機器及IP 50 'orakill ' || g.instance_name || ' ' || d.spid "Windows殺進程", 51 'kill ' || d.spid "UnixORLinux殺進程1", 52 'kill -9 ' || d.spid "UnixORLinux殺進程2" -- 用1殺不掉就加-9 53 /* 54 不管是在數據庫用disconnect還是上面到操作系統上面敲kill命令,都是殺的進程, 55 殺掉操作系統進程是一件危險的事情,千萬不得誤殺,請務必謹慎操作,嚴格確認。 56 */ 57 from user_jobs a, 58 dba_jobs_running b, 59 gv$session c, 60 gv$process d, 61 gv$instance g 62 where a.job = b.job 63 and b.sid = c.sid 64 and c.paddr = d.addr 65 and g.inst_id = c.inst_id; 66 67 /*** 第四步:恢復JOB,使其繼續執行 ***/ 68 -- 如果JOB未修復好,可不執行此步操作 69 begin 70 dbms_job.broken(job編號, false); 71 -- dbms_job.broken(job編號, false, 可加個參數修改接來下運行的時間原默認為sysdate); 72 commit; 73 end; 74 /
作者:滾雪球俱樂部-何理利
出處: http://www.cnblogs.com/snowballed/
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出 原文鏈接。
如有疑問, 可郵件(he.lili1@ztesoft.com)咨詢。