Event直译对应的中文解释是指事件,不过单纯讲事件毕竟太抽象了,举个示例来形容吧。A(对应某个应用程序,或者是ORACLE中的进程)在干活时突然眉头一皱说道,不好,前方有情况,这可怎么办!这时,只见它认真想了想,过了一会儿脸上一喜说道:有了,俗话说早请示啊晚汇报,出现情况要找领导,赶紧给领导发消息呗!于是B(也是对应某个应用或ORACLE进程)就收到了一条A发过来的"前方有XX情况"的消息,这个过程就叫EVENT(含A发消息以及B接收消息)。
SCHEDULER 中有两种触发EVENT的情况:
Scheduler 中触发的Events,一般是说当前schduler中job的状态发生修改,类似job启动,或者运行结束,或者达到运行时间等诸如此类的动作,都能够抛出一个EVENT,接收到EVENT的applicate就可以根据这些信息进行适当的处理。
比如说,由于系统太过于繁忙,超出job启动时间后30分钟,job仍然没能顺利启动,那么这个时候,Scheduler就可以抛出一条EVENT给外部的应用,以便外部应用能够及时通知DBA,进行处理。
外部的应用也可以触发Events,并且由Scheduler来接收并处理这一类型的Events。所谓Scheduler处理EVENT就是指Scheduler启动相应的job来执行相关操作,这类job在创建时专门声明了event的处理,这样当接收到EVENT时,这类job就会启动。
Scheduler 使用Oracle高级队列来抛出以及销毁Events。当抛出Schduler触发的Events时,Scheduler将消息入队到默认的event队列,application则通过检查该队列来处理Events。当抛出application触发的Events时,application将消息入队到处理job对应的队列中。
下面我们也按照这两个类型来介绍Scheduler中的Events。
前面说了,Scheduler抛出的Events一般是指job状态改变时触发的,那么是不是说只要job状态发生了改变,就会触发Events,其实并非如此,因为默认情况下,job是不触发Events的。
Scheduler 中的job有一个属性叫raise_events,专门用来设置job触发Events的条件,该属性在CREATE_JOB时不能执行,因此默认情况下该属性不会赋值,自然也就不会触发EVENT。要设置raise_events属性,只能是在job创建完成后,通过SET_ATTRIBUTE过程修改job的raise_events属性。
例如,修改前面创建的job-,启用raise_events属性,执行语句如下:
SQL> BEGIN
2 DBMS_SCHEDULER.SET_ATTRIBUTE('INSERT_TEST_TBL', 'raise_events', DBMS_SCHEDULER.JOB_ALL_EVENTS)
3 END;
4 /
PL/SQL procedure successfully completed.上述示例中指定的raise_events属性的属性值DBMS_SCHEDULER.JOB_ALL_EVENTS,就是抛出Events的触发条件。
触发Events的有下列的类型,分别代表不同的操作:
起用raise_events后,Scheduler就会按照设定的触发条件,当达到触发条件时,即会抛出事件信息到SYS.SCHEDULER$_EVENT_QUEUE队列。
例如,手动执行一次INSERT_TEST_TBL,看看是否向队列中记录信息,操作如下:
SQL> exec dbms_scheduler.run_job('INSERT_TEST_TBL');
PL/SQL procedure successfully completed.执行下列脚本,出队数据:
SQL> set serveroutput on
SQL> DECLARE
2 l_dequeue_options DBMS_AQ.dequeue_options_t;
3 l_message_properties DBMS_AQ.message_properties_t;
4 l_message_handle RAW(16);
5 l_queue_msg sys.scheduler$_event_info;
6 BEGIN
7 l_dequeue_options.consumer_name := 'TEST';
8
9 DBMS_AQ.dequeue(queue_name => 'SYS.SCHEDULER$_EVENT_QUEUE',
10 dequeue_options => l_dequeue_options,
11 message_properties => l_message_properties,
12 payload => l_queue_msg,
13 msgid => l_message_handle);
14 COMMIT;
15
16 DBMS_OUTPUT.put_line('event_type : ' || l_queue_msg.event_type);
17 DBMS_OUTPUT.put_line('object_owner : ' || l_queue_msg.object_owner);
18 DBMS_OUTPUT.put_line('object_name : ' || l_queue_msg.object_name);
19 DBMS_OUTPUT.put_line('event_timestamp: ' || l_queue_msg.event_timestamp);
20 DBMS_OUTPUT.put_line('error_code : ' || l_queue_msg.error_code);
21 DBMS_OUTPUT.put_line('event_status : ' || l_queue_msg.event_status);
22 DBMS_OUTPUT.put_line('log_id : ' || l_queue_msg.log_id);
23 DBMS_OUTPUT.put_line('run_count : ' || l_queue_msg.run_count);
24 DBMS_OUTPUT.put_line('failure_count : ' || l_queue_msg.failure_count);
25 DBMS_OUTPUT.put_line('retry_count : ' || l_queue_msg.retry_count);
26 END;
27 /
event_type : JOB_STARTED
object_owner : TEST
object_name : INSERT_TEST_TBL
event_timestamp: 25-AUG-09 12.49.29.558758 PM +08:00
error_code : 0
event_status : 1
log_id :
run_count : 1
failure_count : 0
retry_count : 0
PL/SQL procedure successfully completed.从返回的信息可以看到,event的类型为JOB_STARTED,表示JOB启动。实际上job:INSERT_TEST_TBL执行一次至少会向队列中插入两条event信息,一条为JOB_STARTED,一条则为JOB_SUCCEEDED(也可能是JOB_FAILED),这里不详细演示,感兴趣的朋友不妨自行测试。
SYS.SCHEDULER$_EVENT_QUEUE 是一个固定队列,实际应用的过程中,DBA应该根据实际情况,将该表访问权限授予相关用户,以便顺利出队该队列中的events信息。
另外,友情提醒,默认情况下Scheduler仅保留最近24小时的Events信息,如果希望修改该设置的话,可以通过SET_SCHEDULER_ATTRIBUTE过程,修改scheduler的event_expiry_time属性,该项属性的属性值以秒为单位。
首先要说明,这里所说的Application是个代词,即可以表示ORACLE数据库之外的应用程序,也可以是ORACLE数据库中的PROCEDURE等对象,总之你就将其理解成用户自己创建的对象就好了。
Scheduler 能够抛出Events让外部应用处理,外部的应用也可以抛出Events让Scheduler启动job处理,不过并不是任何job都能够对外部应用抛出的Events做出响应,必须在创建jobs时明确指定响应的事件。那么如何指定呢?依靠下列两个附加的参数:
下面,我们就演示创建一个由event触发启动的job,在此之前,首先需要进行一些准备工具,比如创建队列,由于队列需要基于一个队列表,因此在创建队列之前,首先要创建一个队列表,考虑到队列表需要依赖一个对象类型,因此在创建队列表之前,先得创建一个type.......复杂,具体的操作步骤如下,客官可要看仔细了:
SQL> create or replace type jss_type 1 as object
2 (
3 event_type VARCHAR2( 1 0),
4 object_owner VARCHAR2( 30 ),
5 object_name VARCHAR2( 3 0)
6 );
7 /
Type created.
SQL> begin
2 dbms_aqadm.create_queue_table(
3 queue_table => 'my_queue_tbl1',
4 queue_payload_type => 'JSS_TYPE1',
5 multiple_consumers => true);
6 end;
7 /
PL/SQL procedure successfully completed.
SQL> begin
2 dbms_aqadm.create_queue(
3 queue_name => 'event_t1',
4 queue_table => 'my_queue_tbl1');
5 end;
6 /
PL/SQL procedure successfully completed.OK, 准备工作完成,下面就来创建一个event触发启动的job,创建脚本如下:
SQL> BEGIN
2 DBMS_SCHEDULER.CREATE_JOB (
3 job_name => 'EVENT_JOB_T1',
4 job_type => 'STORED_PROCEDURE',
5 job_action => 'P_INSERTINTOTEST',
6 event_condition => 'tab.user_data.event_type = ''OP_INSERT''',
7 queue_spec => 'EVENT_T1',
8 enabled => TRUE);
9 END;
10 /
PL/SQL procedure successfully completed.上述脚本仅做演示,因此创建的job仍然执行P_INSERTINTOTEST过程。
三思并不准备再编写一套外部的应用来触发,这里仅为了演示application触发job启动的示例,因此三思决定通过pl/sql直接向event_t1队列中添加消息的方式,触发job的启动,具体操作如下。
首先要执行DBMS_AQADM.START_QUEUE过程,将event_t1置于允许入队和出队状态(默认情况下创建的队列是不允许出队和入队操作的),脚本如下:
SQL> exec dbms_aqadm.start_queue(queue_name => 'event_t1',enqueue => true,dequeue => true);
PL/SQL procedure successfully completed.执行入队操作:
SQL> declare
2 v_Message jss_type1;
3 v_EnqueueOptions dbms_aq.enqueue_options_t;
4 v_MessageProperties dbms_aq.message_properties_t;
5 v_msg_handle raw(16);
6 begin
7 v_message := jss_type1('OP_ SELECT ', user, 'tmpObj');
8
9 dbms_aq.enqueue(queue_name => 'event_t1',
10 enqueue_options => v_enqueueOptions,
11 message_properties => v_messageproperties,
12 payload => v_message,
13 msgid => v_msg_handle);
14 commit;
15
16 end;
17 /
PL/SQL procedure successfully completed.查询队列表中的数据:
SQL> select user_data from my_queue_tbl1;
USER_DATA(EVENT_TYPE, OBJECT_OWNER, OBJECT_NAME)
---------------------------------------------------------
JSS_TYPE1('OP_SELECT', 'TEST', 'tmpObj')然后查询job
SQL> select to_char(created,'yyyy-mm-dd hh24:mi:ss') from jss_1;
TO_CHAR(CREATED,'YY
-------------------
2009-08-25 12:49:29看起来jss_1表中并未有新增加记录,似乎job没有执行啊。这很正常,还记得咱们创建job时指定的 event_condition 条件吗:
没错,只有当event_type为'OP_INSERT'时才会触发job的执行,前面入队时指定的是 OP_ SELECT ,当然没有触发job中指定的procedure啦,下面再次执行入队操作:
SQL> declare
2 v_Message jss_type1;
3 v_EnqueueOptions dbms_aq.enqueue_options_t;
4 v_MessageProperties dbms_aq.message_properties_t;
5 v_msg_handle raw(16);
6 begin
7 v_message := jss_type1('OP_INSERT', user, 'tmpObj');
8
9 dbms_aq.enqueue(queue_name => 'event_t1',
10 enqueue_options => v_enqueueOptions,
11 message_properties => v_messageproperties,
12 payload => v_message,
13 msgid => v_msg_handle);
14 commit;
15
16 end;
17 /再次查看jss_1表看看:
SQL> select to_char(created,'yyyy-mm-dd hh24:mi:ss') from jss_1;
TO_CHAR(CREATED,'YY
-------------------
2009-08-25 12:49:29
2009-08-25 13:21:21多了一条记录,说明job已经被自动触发。
最后再补充一句,基于event的job不能通过DBMS_SCHEDULER.RUN_JOB过程执行,否则会触发ORA-00942: table or view does not exist错误。
今天要来认识一位新同学:CHAIN(注意不要敲成CHINA)。CHAIN可以被视做一组Programs的复合,举个简单的例子:运行PROGRAM:A以及PROGRAM:B,如果成功的话继续运行PROGRAM:C,否则的话运行PROGRAM:D。Programs:A、B、C、D以及执行的逻辑关系就构成了一个最简单的CHAIN。
关于链的管理操作比较多,比如创建/删除/修改链,添加/修改/删除连锁步骤等等。
SQL> DESC dbms_scheduler.create_chain;
参数类型模式的默认?
------------------- ---------------------- ---- ----- ---
CHAIN_NAME VARCHAR2 IN
在Y RULE_SET_NAME VARCHAR2
在Y第二EVALUATION_INTERVAL INTERVAL DAY
在Y的意见VARCHAR2
SQL> EXEC dbms_scheduler.create_chain('my_chain1“);
PL / SQL过程已成功完成。定义好的链条,可以通过* _SCHEDULER_CHAINS视图查看,例如:
SQL>从user_scheduler_chains的选择chain_name;
CHAIN_NAME
------------------------------
MY_CHAIN1步骤以及链中的规则。
连锁步骤就是用来指定链执行的操作及执行步骤,创建链
SQL>开始
2 DBMS_SCHEDULER.DEFINE_CHAIN_STEP(
3 chain_name =>'my_chain1'
4 step_name =>'my_step1'
5 PROGRAM_NAME =>'p_p1');
6月末;
7 /
PL / SQL过程已成功完成。连锁步骤
下面接着为my_chain1添加两个步骤,操作如下:
SQL>开始
2 DBMS_SCHEDULER.DEFINE_CHAIN_STEP(
3 chain_name =>'my_chain1'
4 step_name =>'my_step2'
5 PROGRAM_NAME =>'p_p2');
6 DBMS_SCHEDULER.DEFINE_CHAIN_STEP(
7 chain_name =>'my_chain1'
8 step_name =>'my_step3“
9 PROGRAM_NAME =>'p_p3');
10日结束;
11 /
PL / SQL过程已成功完成。要查询定义的连锁步骤,则是通过* _SCHEDULER_CHAIN_STEPS视图,例如:
SQL> SELECT chain_name,step_name,从user_scheduler_chain_steps PROGRAM_NAME;
CHAIN_NAME STEP_NAME PROGRAM_NAME
-------------------- -------------------- ---------- ----------
MY_CHAIN1 MY_STEP1 P_P1
MY_CHAIN1 MY_STEP2 P_P2
MY_CHAIN1 MY_STEP3 P_P3规则依赖于连锁步骤,每个链的规则都拥有的条件和动作属性,当满足条件时,则执行行动中指定的步骤。
DBMS_SCHEDULER.DEFINE_CHAIN_RULE过程的语法如下:
SQL> DESC dbms_scheduler.define_chain_rule;
参数类型模式的默认?
---------- -------- ---- --------
CHAIN_NAME VARCHAR2 IN
条件VARCHAR2 IN
行动VARCHAR2 IN
在Y RULE_NAME VARCHAR2
在Y的意见VARCHAR2CHAIN_NAME
甚至于,还可以制定成下列逻辑语法:
比如说,我们希望条件为第一步成功运行,那么可以指定条件参数值如下:
行动
例如,创建链
SQL> BEGIN
2 DBMS_SCHEDULER.DEFINE_CHAIN_RULE(
3 chain_name =>'my_chain1'
4条件=>“真”,
5行动=>'开始my_step1',
6 rule_name =>'my_rule1');
7 DBMS_SCHEDULER.DEFINE_CHAIN_RULE(
8 chain_name =>'my_chain1“
9条件=>'my_step1完成“,
10行动=>'开始my_step2',
11 rule_name =>'my_rule2');
(12 DBMS_SCHEDULER.DEFINE_CHAIN_RULE
13 chain_name =>'my_chain1'
14条件=>'my_step2完成“,
15行动0'=>'结束,
16 rule_name =>'my_rule3');
17尾;
18 /
PL / SQL过程已成功完成。
SQL> BEGIN
2 DBMS_SCHEDULER.RUN_CHAIN(
3 chain_name =>'my_chain1'
4 start_steps =>'my_step1');
5月底;
6 /
PL / SQL过程已成功完成。
SQL> SELECT从jss_t2;
TP的DT
---------- ------------
p_p1插入03 - SEP - 09
p_p2插入03 - SEP - 09你看,jss_t2表中有了两条记录,对应前面设定的链式法则,说明my_step1和my_step2均已正确执行。
SQL> BEGIN
2 DBMS_SCHEDULER.CREATE_JOB(
3 JOB_NAME =>'chain_job_1'
4工作类型=>'链',
5 job_action =>'my_chain1'
6 repeat_interval =>'FREQ =每日;间隔= 1',
7启用=> TRUE);
8月底;
9 /
PL / SQL过程已成功完成。基本上碰到修改CHAIN属性的机率不会太大,因此确实没啥可修改的,对于CHAIN对象来说,能够修改的属性只有两个:evaluation_interval和comments,这两个参数一般情况下甚至都不会进行设置。如果你碰到了确实需要修改的情况,没问题,DBMS_SCHEDULER.SET_ATTRIBUTE过程还记的吧,没错,修改CHAIN也是用它。例如:
SQL> select chain_name,comments from user_scheduler_chains;
CHAIN_NAME COMMENTS
-------------------- --------------------------
MY_CHAIN1
SQL> exec dbms_scheduler.set_attribute('my_chain1','comments','change it for a test!');
PL/SQL procedure successfully completed.
SQL> select chain_name,comments from user_scheduler_chains;
CHAIN_NAME COMMENTS
-------------------- --------------------------
MY_CHAIN1 change it for a test !修改Chain Step的运行属性就不能使用DBMS_SCHEDULER.SET_ATTRIBUTE了,而是有专门的过程DBMS_SCHEDULER.ALTER_CHAIN处理,该过程的定义如下:
SQL> desc dbms_scheduler.alter_chain;
Parameter Type Mode Default?
---------- -------- ---- --------
CHAIN_NAME VARCHAR2 IN
STEP_NAME VARCHAR2 IN
ATTRIBUTE VARCHAR2 IN
VALUE BOOLEAN IN前两个参数就不说了,ATTRIBUTE参数用来指定STEP的属性值,可设定的属性值有3个,每个属性值都有TRUE和FALSE两个选项,由VALUE参数指定:
DBMS_SCHEDULER.ALTER_CHAIN 过程修改Chain Step属性后,只有当下次运行时才会生效,如果要修改当前运行中Chain Step的属性,也有一个专门的过程DBMS_SCHEDULER.ALTER_RUNNING_CHAIN进行处理,该过程语法与DBMS_SCHEDULER.ALTER_CHAIN一模一样,这里就不详细介绍了。
Chain Rules 没有对应的修改方法,如果要修改某个Chain的rule,只能首先删除不适当的rule,然后重新添加新rule(所谓添加,其实就是再重新定义一个rule)。
删除Chain Rule有专门的过程DBMS_SCHEDULER.DROP_CHAIN_RULE,该过程语法如下:
SQL> desc dbms_scheduler.drop_chain_rule;
Parameter Type Mode Default?
---------- -------- ---- --------
CHAIN_NAME VARCHAR2 IN
RULE_NAME VARCHAR2 IN
FORCE BOOLEAN IN Y三思一眼就能看出来,这个过程的调用方式那是相当简单,因此就不对各个参数详细介绍了,下面举个简单的示例,比如删除前面定义的my_rule3,执行过程如下:
SQL> exec dbms_scheduler.drop_chain_rule('my_chain1','my_rule3',true);
PL/SQL procedure successfully completed.删除Chain Step也有专门的过程DBMS_SCHEDULER.DROP_CHAIN_STEP进行处理,该过程语法如下:
SQL> desc dbms_scheduler.drop_chain_step;
Parameter Type Mode Default?
---------- -------- ---- --------
CHAIN_NAME VARCHAR2 IN
STEP_NAME VARCHAR2 IN
FORCE BOOLEAN IN Y看着有点儿眼熟是吧,没错,与drop_chain_rule的相似度高达90%以上。例如,删除之前定义的my_step3,执行过程如下:
SQL> exec dbms_scheduler.drop_chain_step('my_chain1','my_step3',true);
PL/SQL procedure successfully completed.如果要删除Chain那就更简单了,执行dbms_scheduler.drop_chain过程即可,例如:
SQL> exec dbms_scheduler.drop_chain('my_chain1',true);
PL/SQL procedure successfully completed.注意,执行drop_chain时,如果不指定force参数为TRUE,那么默认情况下ORACLE会首先检查要删除的CHAIN是否还有被依赖的对象,如果存在的话,会报ORA-27479错误,提示仍然有依赖的对象(所谓依赖的对象就是指,该chain仍然存在chain_step或chain_rule之类),因此无法直接删除。这种情况下解决方案有两种:一是手动删除所有相关的chain_step和chain_rule,然后再执行chain的删除,再就是附加force参数并指定参数值为true,这样ORACLE就会自动替你清除所有依赖的对象了。
==============================================
##转自http://blog.sina.com.cn/s/blog_607cba070100wcvt.html