對于JAVA系統中的定時操作有兩種實現方式(針對oarcle):
1. 通過程序在應用層實現,如quartz,Timer等
如在spring中:
<bean id="abcJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="abcService"/></property>
<property name="targetMethod"><value>abc</value></property>
</bean>
<bean id="abcTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="abcJobDetail"/>
</property>
<property name="cronExpression">
<value>0 0 4 * * ?</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="abcTrigger"/>
</list>
</property>
</bean>
2. 直接在數據庫層實現,先寫個存儲過程,然后創建一個job,定時執行該存儲過程。
具體方法如下:
DBMS_JOB系統包是Oracle“任務隊列”子系統的API編程接口。DBMS_JOB包對于任務隊列提供了下面這些功能:提交并且執行一個任務、改變任務的執行參數以及刪除或者臨時掛起任務等。
DBMS_JOB包中所有的過程都有一組相同的公共參數,用于定義任務,任務的運行時間以及任務定時運行的時間間隔。
下面我們來詳細討論這些參數的意義及用法。
1、job參數
job是一個整數,用來唯一地標示一個任務。該參數既可由用戶指定也可由系統自動賦予,這完全取決于提交任務時選用了那一個任務提交過程。DBMS_JOB.SUBMIT過程通過獲得序列SYS.JOBSEQ的下一個值來自動賦予一個任務號。該任務號是作為一個OUT參數返回的,所以調用者隨后可以識別出提交的任務。而DBMS_JOB.ISUBMIT過程則由調用者給任務指定一個識別號,這時候,任務號的唯一性就完全取決于調用者了。
2、what
what參數是一個可以轉化為合法PL/SQL調用的字符串,該調用將被任務隊列自動執行。在what參數中,如果使用文字字符串,則該字符串必須用單引號括起來。 what參數也可以使用包含我們所需要字符串值的VARCHAR2變量。實際的PL/SQL調用必須用分號隔開。在PL/SQL調用中如果要嵌入文字字符串,則必須使用兩個單引號。
what參數的長度在Oracle7.3中限制在2000個字節以內,在Oracle 8.0以后,擴大到了4000個字節,這對于一般的應用已完全足夠。該參數的值一般情況下都是對一個PL/SQL存儲過程的調用。在實際應用中,盡管可以使用大匿名Pl/SQL塊,但建議大家最好不要這樣使用。還有一個實際經驗就是最好將存儲過程調用封裝在一個匿名塊中,這樣可以避免一些比較莫名錯誤的產生。我來舉一個例子,一般情況下,what參數可以這樣引用:
what =>‘my_procedure(parameter1);’
但是比較安全的引用,應該這樣寫:
what =>‘begin my_procedure(parameter1); end;’
3、next_date Next_
date參數是用來調度任務隊列中該任務下一次運行的時間。這個參數對于DBMS_JOB.SUBMIT和DBMS_JOB.BROKEN這兩個過程缺省為系統當前時間,也就是說任務將立即運行。
當將一個任務的next_date參數賦值為null時,則該任務下一次運行的時間將被指定為4000年1月1日,也就是說該任務將永遠不再運行。在大多數情況下,這可能是我們不愿意看到的情形。但是,換一個角度來考慮,如果想在任務隊列中保留該任務而又不想讓其運行,將next_date設置為null卻是一個非常簡單的辦法。
Next_date也可以設置為過去的一個時間。這里要注意,系統任務的執行順序是根據它們下一次的執行時間來確定的,于是將next_date參數設置回去就可以達到將該任務排在任務隊列前面的目的。這在任務隊列進程不能跟上將要執行的任務并且一個特定的任務需要盡快執行時是非常有用的。
4、Interval
Internal參數是一個表示Oracle合法日期表達式的字符串。這個日期字符串的值在每次任務被執行時算出,算出的日期表達式有兩種可能,要么是未來的一個時間要么就是null.這里要強調一點:很多開發者都沒有意識到next_date是在一個任務開始時算出的,而不是在任務成功完成時算出的。
當任務成功完成時,系統通過更新任務隊列目錄表將前面算出的next_date值置為下一次任務要運行的時間。當由interval表達式算出next_date是null時,任務自動從任務隊列中移出,不會再繼續執行。因此,如果傳遞一個null值給interval參數,則該任務僅僅執行一次。
6. no_parse參數
指示此工作在提交時或執行時是否應進行語法分析
TRUE指示此PL/SQL代碼在它第一次執行時應進行語法分析,
而FALSE指示本PL/SQL代碼應立即進行語法分析。
算法任務重復運行的時間間隔取決于interval參數中設置的日期表達式。下面就來詳細談談該如何設置interval參數才能準確滿足我們的任務需求。一般來講,對于一個任務的定時執行,有三種定時要求。
在一個特定的時間間隔后,重復運行該任務。
在特定的日期和時間運行任務。
任務成功完成后,下一次執行應該在一個特定的時間間隔之后。
第一種調度任務需求的日期算法比較簡單,即'SYSDATE+n',這里n是一個以天為單位的時間間隔。表6給出了一些這種時間間隔設置的例子。
第二種調度任務需求相對于第一種就需要更復雜的時間間隔(interval)表達式,表是一些要求在特定的時間運行任務的interval設置例子。
CREATE OR REPLACE PROCEDURE raise_salary (emp_id INTEGER, increase REAL) IS
current_salary REAL;
salary_missing EXCEPTION;
BEGIN
SELECT sal INTO current_salary FROM emp
WHERE empno = emp_id;
IF current_salary IS NULL THEN
RAISE salary_missing;
ELSE
UPDATE emp SET sal = sal + increase
WHERE empno = emp_id;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO emp_audit VALUES (emp_id, 'No such number');
WHEN salary_missing THEN
INSERT INTO emp_audit VALUES (emp_id, 'Salary is null');
END raise_salary;
1. 通過程序在應用層實現,如quartz,Timer等
如在spring中:
<bean id="abcJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject"><ref bean="abcService"/></property>
<property name="targetMethod"><value>abc</value></property>
</bean>
<bean id="abcTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="abcJobDetail"/>
</property>
<property name="cronExpression">
<value>0 0 4 * * ?</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="abcTrigger"/>
</list>
</property>
</bean>
2. 直接在數據庫層實現,先寫個存儲過程,然后創建一個job,定時執行該存儲過程。
具體方法如下:
DBMS_JOB系統包是Oracle“任務隊列”子系統的API編程接口。DBMS_JOB包對于任務隊列提供了下面這些功能:提交并且執行一個任務、改變任務的執行參數以及刪除或者臨時掛起任務等。
DBMS_JOB包中所有的過程都有一組相同的公共參數,用于定義任務,任務的運行時間以及任務定時運行的時間間隔。
下面我們來詳細討論這些參數的意義及用法。
1、job參數
job是一個整數,用來唯一地標示一個任務。該參數既可由用戶指定也可由系統自動賦予,這完全取決于提交任務時選用了那一個任務提交過程。DBMS_JOB.SUBMIT過程通過獲得序列SYS.JOBSEQ的下一個值來自動賦予一個任務號。該任務號是作為一個OUT參數返回的,所以調用者隨后可以識別出提交的任務。而DBMS_JOB.ISUBMIT過程則由調用者給任務指定一個識別號,這時候,任務號的唯一性就完全取決于調用者了。
2、what
what參數是一個可以轉化為合法PL/SQL調用的字符串,該調用將被任務隊列自動執行。在what參數中,如果使用文字字符串,則該字符串必須用單引號括起來。 what參數也可以使用包含我們所需要字符串值的VARCHAR2變量。實際的PL/SQL調用必須用分號隔開。在PL/SQL調用中如果要嵌入文字字符串,則必須使用兩個單引號。
what參數的長度在Oracle7.3中限制在2000個字節以內,在Oracle 8.0以后,擴大到了4000個字節,這對于一般的應用已完全足夠。該參數的值一般情況下都是對一個PL/SQL存儲過程的調用。在實際應用中,盡管可以使用大匿名Pl/SQL塊,但建議大家最好不要這樣使用。還有一個實際經驗就是最好將存儲過程調用封裝在一個匿名塊中,這樣可以避免一些比較莫名錯誤的產生。我來舉一個例子,一般情況下,what參數可以這樣引用:
what =>‘my_procedure(parameter1);’
但是比較安全的引用,應該這樣寫:
what =>‘begin my_procedure(parameter1); end;’
3、next_date Next_
date參數是用來調度任務隊列中該任務下一次運行的時間。這個參數對于DBMS_JOB.SUBMIT和DBMS_JOB.BROKEN這兩個過程缺省為系統當前時間,也就是說任務將立即運行。
當將一個任務的next_date參數賦值為null時,則該任務下一次運行的時間將被指定為4000年1月1日,也就是說該任務將永遠不再運行。在大多數情況下,這可能是我們不愿意看到的情形。但是,換一個角度來考慮,如果想在任務隊列中保留該任務而又不想讓其運行,將next_date設置為null卻是一個非常簡單的辦法。
Next_date也可以設置為過去的一個時間。這里要注意,系統任務的執行順序是根據它們下一次的執行時間來確定的,于是將next_date參數設置回去就可以達到將該任務排在任務隊列前面的目的。這在任務隊列進程不能跟上將要執行的任務并且一個特定的任務需要盡快執行時是非常有用的。
4、Interval
Internal參數是一個表示Oracle合法日期表達式的字符串。這個日期字符串的值在每次任務被執行時算出,算出的日期表達式有兩種可能,要么是未來的一個時間要么就是null.這里要強調一點:很多開發者都沒有意識到next_date是在一個任務開始時算出的,而不是在任務成功完成時算出的。
當任務成功完成時,系統通過更新任務隊列目錄表將前面算出的next_date值置為下一次任務要運行的時間。當由interval表達式算出next_date是null時,任務自動從任務隊列中移出,不會再繼續執行。因此,如果傳遞一個null值給interval參數,則該任務僅僅執行一次。
6. no_parse參數
指示此工作在提交時或執行時是否應進行語法分析
TRUE指示此PL/SQL代碼在它第一次執行時應進行語法分析,
而FALSE指示本PL/SQL代碼應立即進行語法分析。
算法任務重復運行的時間間隔取決于interval參數中設置的日期表達式。下面就來詳細談談該如何設置interval參數才能準確滿足我們的任務需求。一般來講,對于一個任務的定時執行,有三種定時要求。
在一個特定的時間間隔后,重復運行該任務。
在特定的日期和時間運行任務。
任務成功完成后,下一次執行應該在一個特定的時間間隔之后。
第一種調度任務需求的日期算法比較簡單,即'SYSDATE+n',這里n是一個以天為單位的時間間隔。表6給出了一些這種時間間隔設置的例子。
第二種調度任務需求相對于第一種就需要更復雜的時間間隔(interval)表達式,表是一些要求在特定的時間運行任務的interval設置例子。
CREATE OR REPLACE PROCEDURE raise_salary (emp_id INTEGER, increase REAL) IS
current_salary REAL;
salary_missing EXCEPTION;
BEGIN
SELECT sal INTO current_salary FROM emp
WHERE empno = emp_id;
IF current_salary IS NULL THEN
RAISE salary_missing;
ELSE
UPDATE emp SET sal = sal + increase
WHERE empno = emp_id;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO emp_audit VALUES (emp_id, 'No such number');
WHEN salary_missing THEN
INSERT INTO emp_audit VALUES (emp_id, 'Salary is null');
END raise_salary;