1.包规范
2.包体
包规范定义
create or replace package emp_pkg as
type emp_tab is table of emp%ROWTYPE index by binary_integer;
type emprectyp is record(
emp_no number,
sal number
);
cursor desc_salary return emprectyp;
procedure hire_employee(p_empno, number,p_ename varchar2,p_job varchar2,p_mgr number,p_sal number,p_comm number,p_deptno number);
procedure fire_employee(p_emp_id number);
end emp_pkg;
包体定义
create or replace package body emp_package
as
cursor desc_salary return emprectyp is select empno,sal from emp order by sal desc;
procedure hire_employee(p_empno number,p_ename varchar2,p_job varchar2,p_mgr number,p_sal number,p_comm number,p_deptno number)
is
begin
insert into emp values(p_empno,p_ename,p_job,p_mgr,p_sal,p_comm,p_deptno);
end;
procedure fire_employee(p_emp_id number) is
begin
delete from emp where empno=emp_id;
end;
end emp_package;
1.模块化设计:通过将逻辑相关的类型,常量,变量,异常和子程序放到一个命名的PLSQL模块中,使得每一个包都容易理解,有助于模块化程序的开发。
2.规范化的程序设计:在基于包的应用程序设计,可以首先规划并在包规范中定义包需要提供的功能,即便当前并没有实现包体,也可以编译包规范部分,然后引用该包的存储子程序会被编译。
3.实现信息的隐藏:包规范中定义的常量,变量和异常及子程序等是公有的,可以被外部访问,可以规划将哪些内容公开给外部进行调用,如果不想对外公开,可以再包体中定义这些内容,这样就可以实现信息的隐藏。
4.提供了良好的性能体验:由于在首次打开包子程序时,整个包都会被加载到内存中,因而后续的调用只需要从内存中读取而不需要再次读取磁盘,提供较好的
性能
调用包组件
使用 包名.元素名 这样的形式
当包第一次被调用的时候,将进行初始化,比如将包从硬盘上调到内存中来,放到系统全局工作区的共享缓冲池中,包的运行状态则被放入用户全局区的会话存储区中。因此可以保证每个调用包的会话都拥有包的运行副本,当会话结束时,包的运行状态才会被释放,这也就是说,包从第一次调用被初始化一直到会话结束才释放其运行状态,因此包中的变量具有会话级的作用域,因而可以跨多个事务存储数据。
begin
emp_action_pkg.v_deptno:=30;
dbms_output.put_line(emp_action_pkg.getratisedsalary(7369));
end;
begin
emp_action_pkg.v_deptno:=50;
emp_action_pkg.newdept(45,'采纳部','佛山');
end;
begin
dbms_output.put_line(emp_action_pkg.v_deptno);
end;
包的这种特性使得开发人员可以在包中保存跨多个事务的数据,这大大方便了复杂的程序逻辑的中间数据的存储,而不用特意地用一个表来存储临时的数据
如果在定义包规范时,指定了编译提示SERIALLY_REUSABLE,则可以将包的运行状态保存在系统全局工作区,而不是用户全局区,这样每次调用包以后,包的运行状态就会被释放,这样再次调用包时,将重新开始包的状态。
内存的占用量与包的并发调用用户数成正比。
包的重编译
alter package emp_action_pkg compile body;
alter package emp_action_pkg compile package;
alter package emp_action_pkg compile specification;
查看包的源代码
select object_type 对象类型,object_name 对象名称,status 状态 from user_objects where object_type in('PACKAGE','PACKAGE BODY') order by object_type,status,object_name;
select line,text from user_source where name='EMP_ACTION_PKG' AND TYPE='PACKAGE' ORDER BY line;
select line,text from user_source where name='EMP_ACTION_PKG' AND TYPE='PACKAGE BODY' ORDER BY line;
包重载
包重载实际上就是对包中包含的子程序的重载,也就是说一个包里可以有多个名称相同但参数不同的过程或函数,在调用时,PLSQL将通过形式参数进行匹配以便找到不同的重载的子程序。
在包中重载子程序
create or replace package emp_action_pkg_overload is
procedure newdept(
p_deptno dept.deptno%TYPE,
p_dname dept.dname%TYPE,
p_loc dept.loc%TYPE
);
procedure newdept(
p_deptno dept.deptno%TYPE,
p_dname dept.dname%TYPE
);
function getraisedsalary(p_empno emp.empno%TYPE)
return number;
function getraisedsalary(p_ename emp.ename%TYPE)
return number;
end emp_action_pkg_overload;
包含重载子程序的包体实现
create or replace package body emp_action_pkg_overload is
procedure newdept(
p_deptno dept.deptno%TYPE,
p_dname dept.dname%TYPE,
p_loc dept.loc%TYPE
)
AS
v_deptcount number;
begin
select count(*) into v_deptcount from dept where deptno=p_deptno;
if v_deptcount>0
then
raise_application_error(-20002,'出现了相同的员工记录');
end if;
insert into dept(deptno,dname,loc) values(p_deptno,p_dname,p_loc);
end newdept;
procedure newdept(
p_deptno dept.deptno%TYPE,
p_dname dept.dname%TYPE
)
AS
v_deptcount number;
begin
select count(*) into v_deptcount from dept where deptno=p_deptno;
if v_deptcount>0
then
raise_application_error(-20002,'出现了相同的员工记录');
end if;
insert into dept(deptno,dname,loc)values (p_deptno,p_dname,'中国');
end newdept;
function getraisedsalary(p_empno emp.empno%TYPE)
return number
is
v_job emp.job%TYPE;
v_sal emp.sal%TYPE;
v_salaryraise number(10,2);
begin
select job,sal into v_job,v_sal from emp where empno=p_empno;
cass v_job
when '职员' then
v_salaryratio:=1.09;
when '销售人员' then
v_salaryratio:=1.18;
when '经理' then
v_salaryratio:=1.11;
else
v_salaryratio:=1;
end case;
if v_salaryratio<>1;
then
return round(v_sal * v_salaryratio,2);
else
return v_sal;
end if;
exception
when no_data_found then
return 0;
end getraisedsalary;
function getraisedsalary(p_ename emp.ename%TYPE)
return number
is
v_job emp.job%TYPE;
v_sal emp.sal%TYPE;
v_salaryratio number(10,2);
begin
select job,sal into v_job,v_sal from emp where ename=p_ename;
case v_job
when '职员' then
v_salaryratio:=1.09;
when '销售人员' then
v_salaryratio:=1.18;
when '经理' then
v_salaryratio:=1.11;
else
v_salaryratio:=1;
end case;
if v_salaryratio<>1;
then
return round(v_sal * v_salaryratio,2);
else
return v_sal;
end if;
exception
when no_data_found then
return 0;
end getraisedsalary;
function checkdeptno(p_deptno dept.deptno%TYPE) return number
as
v_counter number(2);
begin
select count(*) into v_couonter from dept where deptno=p_deptno;
return v_counter;
end;
end emp_action_pkg_overload;
调用
declare
v_sal number(10,2);
begin
emp_action_pkg_overload.newdept(43,'样品部','京东');
emp_action_pkg_overload.newdept(44,'纸品部');
v_sal:=emp_action_pkg_overload.getraisedsalary(7369);
v_sal:=emp_action_pkg_overload.getraisedsalary('史密斯');
end;
下面的重载是无效的
1.function get(p_empno IN number) return number;
function get(p_ename OUT number) return number;
如果参数的名称和参数的模式不同
2.function get(p_empno emp.empno%TYPE) return number;
function get(p_ename emp.ename%TYPE) return varchar2;
如果要重载的两个函数只是在返回的类型上不同
3.function get(p_empno number) return number;
function get(p_ename integer) return number;
包初始化
包可以包含持续整个会话期内的数据结构,因此很多开发人员会考虑在包中放一些比较复杂的数据结构。
create or replace package inittest is
type emp_typ is table of emp%ROWTYPE index by binary_integer;
cursor emp_cur return emp%ROWTYPE;
curr_time number;
emp_tab emp_typ;
procedure newdept(
p_deptno dept.deptno%TYPE,
p_dname dept.dname%TYPE,
p_loc dept.loc%TYPE
);
function getraisedsalary(p_empno emp.empno%TYPE)
return number;
end inittest;
create or replace package body inittest is
row_counter number:=1;
cursor emp_cur return emp%ROWTYPE is
select * from emp order by sal desc;
procedure newdept(
p_deptno dept.deptno%TYPE,
p_dname dept.dname%TYPE,
p_loc dept.loc%TYPE
)
as
begin
function getraisedsalary(p_empno emp.empno%TYPE)
return number is
begin
null;
end getraisedsalary;
begin
select to_number(to_char(sysdate,'SSSSS')) into curr_time from dual;
for emp_row in emp_cur loop
emp_tab(row_counter):=emp_row;
row_counter:=row_counter+1;
end loop;
exception
when others then
dbms_output.put_line('出现了异常');
end inittest;
包的纯度级别
正如自定义函数可以在sql语句中直接使用一样,包中的公共函数也可以在sql语句中直接使用。同样,如果要在sql中使用这些包中的公共函数,需要对公共函数的定义加以限制,比如公共函数不能包含DML语句,不能读写远程包的变量。这些可以通过包的纯度级别来进行限制。
WNDS:限制函数不能修改数据库数据,即禁止函数执行DML操作。
WNPS:限制函数不能修改包变量,即不能为包变量赋值
RNDS:用于限制函数不能读取数据库数据,也就是禁止执行select操作
RNPS:用于限制函数不能读取包变量,也就是不能将包变量赋值给其他变量.
要在包中使用包纯度级别,必须首先在包规范中定义函数,然后指定函数的纯度级别。
create or replace package puritytest is
type dept_typ is table of dept%ROWTYPE index by binary_integer;
dept_tab dept_typ;
procedure newdept(
p_deptno dept.deptno%TYPE,
p_dname dept.dname%TYPE,
p_loc dept.loc%TYPE
);
function getraisedsalary(p_empno emp.empno%TYPE)
return number;
pragma restrict_references(newdept,WNPS);
pragma restrict_references(getraisedsalary,WNDS);
end puritytest;
如果在包体中违反了纯度级别,越过了,就会报错。
如果要编写可被SQL语句引用的包的公用函数,函数必须要符合WNDS,WNPS和RNPS这3个纯度级别。
包权限设置
包提供了AUTHID语句来设置权限,只能在包规范中定义权限,包内的单独子程序必须全部是调用者子程序或定义者子程序,而不能进行混合。
create or replace package emp_action_pkg
AUTHID current_user is
v_deptno number(3):=20;
procedure newdept(
p_deptno dept.deptno%TYPE,
p_dname dept.dname%TYPE,
p_loc dept.loc%TYPE
);
function getraisedsalary(p_empno emp.empno%TYPE)
return number;
end emp_action_pkg;
在包中使用游标
由于包的这种会话级别存储数据的特性,因此可以在包中定义游标。
1.在包规范中定义整个游标,包含查询语句,这与在本地PL/SQL块中定义游标非常相似。
2.仅定义一个游标头而不包含查询语句,在这种情况下,只有在包体中指定查询,隐藏了游标的实现细节
如果在包中仅定义游标头,那么必须要使用return子句来指定游标将提取的数据的元素类型,当然这个类型一般是有游标的select语句确定的记录类型。一般return子句定义如下两种类型:
1.使用%ROWTYPE属性定义的记录类型
2.用户自定义的记录类型
在包规范中声明游标
create or replace package emp_pkg as
type emp_tab is table of emp%ROWTYPE index by binary_integer;
type emprectyp is record(
emp_no number,
sal number
);
cursor desc_salary return emprectyp;
cursor emp_cur(p_deptno IN dept.deptno%TYPE) is
select * from emp where deptno=p_deptno;
procedure hire_employee(p_empno number,p_ename varchar2,p_job varchar2,p_mgr number,p_sal number,p_comm number,p_deptno number);
procedure fire_employee(p_emp_id number);
end emp_pkg;
包体中定义游标查询
create or replace package body emp_pkg
as
cursor desc_salary return emprectyp is
select empno,sal from emp order by sal desc;
procedure hire_employee(p_empno number,p_ename varchar2,p_job varchar2,p_mgr number,p_sal number,p_comm number,p_deptno number,p_hiredate DATE) is
begin
for emp_salrow in desc_salary loop
dbms_output.put_line(emp_salrow.emp_no||':'||emp_salrow.sal);
end loop;
end;
procedure fire_employee(p_emp_id number) is
begin
delete from emp where empno=p_emp_id;
for emp_row in emp_cur(20) loop
dbms_output.put_line(emp_row.empno||' '||emp_row.deptno);
end loop;
end;
end emp_pkg;
由于游标的作用并不局限于某个特定的PL/SQL块,因此可以先在某个子程序中打开一个打包的游标,然后不直接关闭,使它一直保持打开的状态以便由其他的包,块或子程序调用,最后另外关闭或退出oracle会话
检查包的依赖性
在oracle中,包头不依赖于包体,也就是说可以改变包体而不影响包头的对象。
由于包体要依赖包头,同时包体依赖于emp表,但是包头并不依赖于包体或emp表,因此如果对包体进行改变,那么并不影响包头的状态,包头并不需要重新翻译。但是如果包头发生了改变,将会使包体自动失效,因为包体紧密依赖包头。
1.sql 查询包 包规范 有效性
select object_name,object_type,status from user_objects where object_name IN('EMP_PKG_DEPENDENCY','EMP');
使用系统包
默认情况下,oracle并没有启用DBMS_OUTPUT包,也就是说,如果直接使用DBMS_OUTPUT.PUT_LINE或GET_LINE来输出或获取消息,是看不到任何输出的。因此在使用DBMS_OUTPUT包之前,总要先使用DBMS_OUTPUT.ENABLE来启用包。
DBMS_OUTPUT.ENABLE(buffer_size in integer default 20000);
如果先执行了set serveroutput on 语句,则没有必要使用该过程,因为set serveroutput on 会自动调用该语句。
关闭时 可以DBMS_OUTPUT.DISABLE 或者set serveroutput off
向缓冲区中提取与写入内容
必须要理解的是,DBMS_OUTPUT并不是直接将信息输出到屏幕,而是将数据写入到了一个缓冲区中,然后再次将这些输出读回。当在sql*plus中使用set serveroutput on 命令时,实际上是让sql*plus在每条dbms_output之后检查缓冲区中的内容,然后在屏幕上进行显示。
可以使用如下几个过程来向缓冲区中输入消息
PUT:将信息写入缓冲区,并不包含换行符
PUT_LINE:将完整的行信息写入缓冲区,包含换行符
NEW_LINE:在行尾添加换行符,在使用put时,必须调用NEW_LINE过程来添加换行符。
可以使用如下几个过程来从缓冲区中提取消息。
GET_LINE:用于取得缓冲区的单行信息
GET_LINES:用于取得缓冲区的多行信息
PUT/PUT_LINE---->将信息写到缓冲区----->DBMS_OUTPUT数据缓冲区<-------从缓冲区中提取数据进行显示<----GET_LINE/GET_LINES-------->屏幕
使用DBMS_PIPE包
DBMS_PIPE包用于在同一个oracle的instance,即例程的不同会话之间进行通信。管道非常类似于UNIX操作系统中的管理,但是oracle管道并不是使用像在UNIX中那样的操作系统调用的机制,其管道信息被缓存在系统全局区SGA中,当关闭oracle例程时,就会丢失管理信息。管道分为两种:
1.公用管道:是指所有数据库用户都可以访问的管道
2.私有管道:私有管道只能由建立管道的数据库用户访问
会话A:管道发送方 会话B:管道接收方
创建管道CREATE_PIPE
|
写信息到缓冲区 从接收缓冲区读取消息
PACK_MESSAGE PACK_MESSAGE
| |
向管道发送信息 从管道接收消息,存储到接收缓冲区
SEND_MESSAGE-------------------->RECEIVE_MESSAGE
1.创建管道CREATE_PIPE
DBMS_PIPE.CREATE_PIPE(pipename IN varchar2,maxpipesize IN integer default 8192,private IN boolean default true)
return integer;
status:=DBMS_PIPE.CREATE_PIPE('privatepipe',8192,true); 创建一个私有管道
status:=DBMS_PIPE.CREATE_PIPE('privatepipe',8192,false); 创建一个公有管道
2.缓存消息PACK_MESSAGE
为了给换到发送消息,必须要先使用过程PACK_MESSAGE将消息写入本地消息缓冲区,然后使用SEND_MESSAGE将本地消息缓冲区中的消息发送到管道。PACK_MESSAGE的功能就是将消息存到私有的信息缓冲区中,该过程具有多个重载过程,分别接收类型为varchar2,number或date类型的数据项。
DBMS_PIPE.PACK_MESSAGE(item IN varchar2);
DBMS_PIPE.PACK_MESSAGE(item IN nchar);
DBMS_PIPE.PACK_MESSAGE_RAW(item IN RAW);
DBMS_PIPE.PIPE_MESSAGE_ROWID(item IN ROWID);
在缓冲区中只能存放4096字节的数据,如果超过了限制,oracle将抛出异常
declare
v_ename emp.ename%TYPE;
v_sal emp.sal%TYPE;
v_rowid ROWID;
v_empno emp.empno%TYPE:=&empno;
begin
select rowid,ename,sal into v_rowid,v_rowid,v_sal from emp where empno=v_empno;
dbms_pipe.pack_message('员工编号:'||v_empno||'员工名称:'||v_ename);
dbms_pipe.pack_message('员工薪资:'||v_sal||'ROWID值:'||v_rowid);
end;
3.发送消息SEND_MESSAGE
declare
v_sendflag int;
begin
v_sendflag:=dbms_pipe.send_message('PUBLIC_PIPE');
if v_sendflag=0 then
dbms_output.put_line('消息成功发送到管道');
end if;
end;
4.接收消息RECEIVE_MESSAGE
receive_message函数用于接收管道信息,将接收到的消息写入本地消息缓冲区,然后删除管道中的消息,因此必须特别注意,管道消息只能被接收一次。
receive_message会在指定的管道不存在时,隐式地创建管道,并且等待接收信息。如果在指定时间内没有接收到消息,调用会返回同时管道自动删除。
declare
v_receiveflag int;
begin
v_receiveflag:=DBMS_PIPE.receive_message('PUBLIC_PIPE');
if v_receiveflag=0 then
dbms_output.put_line('成功的从管道中获取消息');
end if;
end;
5.确定数据类型NEXT_ITEM_TYPE
在调用了receive_message之后,可以使用NEXT_ITEM_TYPE来确定本地消息缓冲区的下一项的数据类型
dbms_pipe.next_item_type return integer;
函数返回值:
0表示无数据项 6表示number 9表示varchar2 11表示rowid 12表示date 23表示raw类型
6.读取缓冲区数据UNPACK_MESSAGE
该过程将从缓冲区中读取消息,和PACK_MESSAGE过程一样,该过程也是重载的,因此能够接收多种类型的参数。
dbms_pipe.unpack_message(item out number);
dbms_pipe.unpack_message_raw_rowid(item out rowid);
参数中的item表示从私有数据缓冲区中接收的数据所保存的变量,如果缓冲区没有数据或类型不匹配,则会触发ORA-06556或ORA-06559,因此最好在接收之前,使用NEXT_ITEM_TYPE函数确定缓冲区中下一个项目的数据类型
declare
v_message varchar2(100);
begin
dbms_pipe.unpack_message(v_message);
dbms_output.put_line(message);
end;
7.删除管道remove_pipe ,清除管道内容remove_pipe, 复位管道缓冲区reset_buffer
8.返回会话名称unique_session_name
该函数用来为特定会话返回唯一的名称,名称的最大长度为30个字节,对于同一会话来说,其值不会改变
管道例子
1.一个会话发送消息到管道时,需要首先将消息写入本地消息缓冲区,然后将本地消息缓冲区内容发送到管道
2.当接收管道消息时,需要首先使用本地消息缓冲区接收管道消息,然后从消息缓冲区取得具体消息
下面是创建2个过程,然后使用这两个过程在不同的会话中发送和接收消息
发送管道消息
create or replace procedure end_pipe_message(pipename varchar2,message varchar2)
is
flag int;
begin
flag:=dbms_pipe.create_pipe(pipename); --创建管道
if flag=0 then --如果管道创建成功
dbms_pipe.pack_message(message); --将消息写到本地缓冲期区
flag:=dbms_pipe.send_message(pipename); --将本地缓冲区中的消息发送到管道
end if;
end;
从管道接收消息
create or replace procedure receive_pipe_message(pipename varchar2,message out varchar2)
is
flag int;
begin
flag:=dbms_pipe.receive_message(pipename); --从管道中获得消息,保存到缓冲区
if flag=0 then
dbms_pipe.unpack_message(message); --从缓冲区读取消息
flag:=dbms_pipe.remove_pipe(pipename); --移除管道
end if;
end;
使用 分别用scott 和userb 登录
scott
sql>exec send_pipe_message('pipe_demo','向管道中发送一条消息');
sql>grant execute on scott.receive_pipe_message to userb;
userb
sql>declare
v_message varchar2(100);
begin
scott.receive_pipe_message('pipe_demo',v_message);
dbms_output.put_line(v_message);
end;
使用DBMS_ALTER
报警是基于事务的,意味着除非能够报警的事务被提交,否则等待过程中的事务不会被报警。
dbms_alter用于生成并传递数据的报警消息,通过在代码中合理地使用该包,可以发生特定数据库事件时将信息传递给应用程序。
发布报警SINGAL------>报警注册REGISTER
|
报警等待(轮询)WAITONE或WAITANY
|
删除报警REMOVE
1.注册报警事件REGISTER
该过程允许注册一个感兴趣的报警,名称以参数输入的形式告之,在一个会话中可以注册多个报警。如果以后不再需要报警,可以使用remove过程从报警注册表中移除
dbms_alter.register(name in varchar2);
2.等待特定报警waitone
该过程用于等待当前会话中特定的报警事件,并且在发生报警事件时输出报警消息,该过程在执行之前,会隐含地发出commit
dbms_alter.waitone(
name in varchar2,
message out varchar2,
status out integer,
timeout in number default maxwait
);
3.等待任意报警waitany
waitany过程会等待会话中已经注册的任何报警的发生,在这个过程执行前会有一个隐含的commit被执行,同样,在等待这个报警发生的同时,还可以首先发布某些报警。
dbms_alter.waitany(
name out varchar2,
message out varchar2,
status out integer,
timeout in number default maxwait
);
4.删除报警remove
5.删除所有报警removeall
6.时间间隔设置set_defaults
7.设置报警消息signal
该过程用于指定报警事件所对应的报警消息,只有在提交事务时才会发出报警消息,而当回退事务时是不会发出报警消息的.
dbms_alter.signal(name in varchar2,message in varchar2);
message指定报警消息 不能超过1800字节
多个会话可以并发执行同一个报警,每个会话发布报警时会阻塞其他会话发布的报警,直到报警被提交,因此事务会以序列的方式发生
演示
同样需要2个会话,在第一个会话创建如下匿名块
declare
v_altername varchar2(30):='alert_demo';
v_status integer;
v_msg varchar2(200);
begin
dbms_alter.register(v_alertname);
dbms_alter.waitone(v_alertname,v_msg,v_status);
if v_status !=0
then
dbms_output.put_line('error');
end if;
dbms_output.put_line(v_msg);
end;
上面代码注册了了一个名为alert_demo的报警,然后调用waiton等待报警,如果在sql*plus 执行这段代码,可以看到整个界面被阻塞了,用来等待有报警产生。
产生报警示例
declare
v_alertname varchar2(30):='alert_demo';
begin
dbms_alert.signal(v_alertname,'这是一个报警信息');
commit;
end;
使用DBMS_JOB包
必须确保设置了初始化参数JOB_QUEUE_PROCESSES的值不为0,才能使用DBMS_JOB对作业进行管理.
1.创建作业submit
dbms_ddl.analyze_object方法可以分析数据表,并且将存储结果存储起来,对于sql的运行效率有较大提升。
定义一个作业
declare
v_jobno number;
begin
dbms_job.submit
(v_jobno,'dbms_ddl.analyze_object(''TABLE'',''SCOTT'',''EMP'',''COMPUTE'');',SYSDATE,'SYSDATE+1');
dbms_output.put_line('获取的作业编号为:'||v_jobno);
commit;
end;
数据字典查询作业
select job,next_date,next_sec,interval,what from user_objects where job=22904;
sysdate+1:表示下一天的当前时间
trunc(sysdate)+1:表示下一天的午时,即12点
trunc(sysdate)+17/24:表示今天的17/24天,也就是从午夜0点以来的17个小时后,即下午5点开始执行。
'null':表示作业立即运行
2.移除作业remove
3.更改作业change
4.更改作业执行what
EXEC dbms_job.what(22904,'emp_pkg_dependency.fire_employee(7369)');
5.更改运行日期NEXT_DATE
6.数据库实例配置instance
7.更改间隔interval
8.中断作业BROKEN
9.强制作业运行RUN
使用RUN过程可以强制作业立即执行,即使作业已经标记为中断,也会强制执行,因为作业在运行完后会计算下一次执行的时间,因此在调用RUN过程之后,下一次的执行时间也会发生改变。
转载于:https://blog.51cto.com/pankuo/1630255