对于
JAVA
系统中的定时操作有两种实现方式
(
针对
oarcle)
:
1.
通过程序在应用层实现,如
quartz
,
Timer
等
如在
spring
中:
<
bean
id
=
"abcJobDetail"
class
=
"org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"
>
<o:p></o:p>
<
property
name
=
"targetObject"
><
ref
bean
=
"abcService"
/></
property
>
<o:p></o:p>
<
property
name
=
"targetMethod"
><
value
>
abc
</
value
></
property
>
<o:p></o:p>
</
bean
>
<o:p></o:p>
<o:p></o:p>
<
bean
id
=
"abcTrigger"
class
=
"org.springframework.scheduling.quartz.CronTriggerBean"
>
<o:p></o:p>
<
property
name
=
"jobDetail"
>
<o:p></o:p>
<
ref
bean
=
"abcJobDetail"
/>
<o:p></o:p>
</
property
>
<o:p></o:p>
<
property
name
=
"cronExpression"
>
<o:p></o:p>
<
value
>
0 0 4 * * ?
</
value
>
<o:p></o:p>
</
property
>
<o:p></o:p>
</
bean
>
<o:p></o:p>
<o:p></o:p>
<
bean
class
=
"org.springframework.scheduling.quartz.SchedulerFactoryBean"
>
<o:p></o:p>
<
property
name
=
"triggers"
>
<o:p></o:p>
<
list
>
<o:p></o:p>
<
ref
local
=
"abcTrigger"
/>
<o:p></o:p>
</
list
>
<o:p></o:p>
</
property
>
<o:p></o:p>
</
bean
>
2.
直接在数据库层实现,先写个存储过程,然后创建一个
job
,定时执行该存储过程。
具体方法如下:
DBMS_JOB
系统包是
Oracle
“任务队列”子系统的
API
编程接口。
DBMS_JOB
包对于任务队列提供了下面这些功能:提交并且执行一个任务、改变任务的执行参数以及删除或者临时挂起任务等。
<v:shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id="_x0000_i1025" style="WIDTH: 387pt; HEIGHT: 258.75pt" type="#_x0000_t75"><v:imagedata o:title="ScreenShot053" src="file:///C:\DOCUME~1\pengch\LOCALS~1\Temp\msohtml1\01\clip_image001.gif"></v:imagedata></v:shape>
<o:p>
</o:p>
DBMS_JOB
包中所有的过程都有一组相同的公共参数,用于定义任务,任务的运行时间以及任务定时运行的时间间隔。这些公共任务定义参数见表
2
所示。
<v:shape id="_x0000_i1026" style="WIDTH: 405pt; HEIGHT: 128.25pt" type="#_x0000_t75"><v:imagedata o:title="ScreenShot054" src="file:///C:\DOCUME~1\pengch\LOCALS~1\Temp\msohtml1\01\clip_image002.gif"></v:imagedata></v:shape>
下面我们来详细讨论这些参数的意义及用法。
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
时,则该任务下一次运行的时间将被指定为<st1:chsdate w:st="on" year="4000" month="1" day="1" islunardate="False" isrocdate="False">
4000
年
1
月
1
日</st1:chsdate>,也就是说该任务将永远不再运行。在大多数情况下,这可能是我们不愿意看到的情形。但是,换一个角度来考虑,
如果想在任务队列中保留该任务而又不想让其运行,将
next_date
设置为
null
却是一个非常简单的办法。
<o:p></o:p>
Next_date
也可以设置为过去的一个时间。这里要注意,系统任务的执行顺序是根据它们下一次的执行时间来确定的,于是将
next_date
参数设置回去就可以达到将该任务排在任务队列前面的目的。这在任务队列进程不能跟上将要执行的任务并且一个特定的任务需要尽快执行时是非常有用的。
4
、
Interval
Internal
参数是一个表示
Oracle
合法日期表达式的字符串。这个日期字符串的值在每次任务被执行时算出,算出的日期表达式有两种可能,要么是未来的一个时间要么就是
null.
这里要强调一点:很多开发者都没有意识到
next_date
是在一个任务开始时算出的,而不是在任务成功完成时算出的。
<o:p></o:p>
当任务成功完成时,系统通过更新任务队列目录表将前面算出的
next_date
值置为下一次任务要运行的时间。当由
interval
表达式算出
next_date
是
null
时,任务自动从任务队列中移出,不会再继续执行。因此,如果传递一个
null
值给
interval
参数,则该任务仅仅执行一次。
6. no_parse
参数
指示此工作在提交时或执行时是否应进行语法分析
TRUE
指示此
PL/SQL
代码在它第一次执行时应进行语法分析,
而
FALSE
指示本
PL/SQL
代码应立即进行语法分析。
算法任务重复运行的时间间隔取决于
interval
参数中设置的日期表达式。下面就来详细谈谈该如何设置
interval
参数才能准确满足我们的任务需求。一般来讲,对于一个任务的定时执行,有三种定时要求。
在一个特定的时间间隔后,重复运行该任务。
在特定的日期和时间运行任务。
任务成功完成后,下一次执行应该在一个特定的时间间隔之后。
第一种调度任务需求的日期算法比较简单,即
'SYSDATE+n'
,这里
n
是一个以天为单位的时间间隔。表
6
给出了一些这种时间间隔设置的例子。
<v:shape id="_x0000_i1027" style="WIDTH: 380.25pt; HEIGHT: 163.5pt" type="#_x0000_t75"><v:imagedata o:title="" src="file:///C:\DOCUME~1\pengch\LOCALS~1\Temp\msohtml1\01\clip_image003.png"></v:imagedata></v:shape>
第二种调度任务需求相对于第一种就需要更复杂的时间间隔(
interval
)表达式,表是一些要求在特定的时间运行任务的
interval
设置例子。
<v:shape id="_x0000_i1028" style="WIDTH: 363.75pt; HEIGHT: 229.5pt" type="#_x0000_t75"> <v:imagedata o:title="" src="file:///C:\DOCUME~1\pengch\LOCALS~1\Temp\msohtml1\01\clip_image005.png"></v:imagedata></v:shape>
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;
对于JAVA系统中的定时操作有两种实现方式(针对oarcle)