oracle scheduler(四)使用Events

来源:互联网 发布:知否小说全文免费阅读 编辑:程序博客网 时间:2024/05/30 07:12

四、使用Events

SCHEDULER 中有两种触发EVENT 的情况:

(1) Scheduler 触发的Events

      Scheduler 中触发的Events,一般是说当前schduler 中job 的状态发生修改,类似job启动,或者运行结束,或者达到运行时间等诸如此类的动作,都能够抛出一个EVENT,接收到EVENT 的application就可以根据这些信息进行适当的处理。

      比如说,由于系统太过于繁忙,超出job 启动时间后30 分钟,job 仍然没能顺利启动,那么这个时候,Scheduler就可以抛出一条EVENT 给外部的应用,以便外部应用能够及时通知DBA,进行处理。

(2) application 触发的Events

      外部的应用也可以触发Events,并且由Scheduler 来接收并处理这一类型的Events。
      所谓Scheduler 处理EVENT 就是指Scheduler 启动相应的job 来执行相关操作,这类job在创建时专门声明了event 的处理,这样当接收到EVENT 时,这类job 就会启动。

      Scheduler 使用Oracle 高级队列来抛出以及销毁Events。当抛出Schduler 触发的Events时,Scheduler 将消息入队到默认的event 队列,application则通过检查该队列来处理Events。当抛出application 触发的Events 时,application将消息入队到处理job 对应的队列中。


4.1 Scheduler抛出的Events

      Scheduler 抛出的Events 一般是指job 状态改变时触发的,默认情况下,job 是不触发Events 的。

      Scheduler 中的job 有一个属性叫raise_events,专门用来设置job 触发Events的条件,该属性在CREATE_JOB时不能执行,因此默认情况下该属性不会赋值,自然也就不会触发EVENT。要设置raise_events属性,只能是在job 创建完成后,通过SET_ATTRIBUTE 过程修改job 的raise_events 属性。

例如,修改前面创建的jobtest,启用raise_events 属性,执行语句如下:

sql> begin

dbms_scheduler.set_attribute('jobtest','raise_events',dbms_scheduler.job_all_events);

end;

/

      上述示例中指定的raise_events属性的属性值dbms_scheduler.job_all_events,就是抛出events的触发条件。

触发Events 的有下列的类型,分别代表不同的操作:

(1)job_started:JOB 启动;

(2) job_succeeded:JOB 成功结束;

(3) job_failed:JOB 执行失败;

(4) job_broken:JOB 被置为BROKEN 状态;

(5) job_completed:JOB 达到最大运行次数,或者运行的结束日期;

(6) job_stopped:JOB 被STOP_JOB 过程置为停止执行的状态;

(7) job_sch_lim_reached:Job 的schedule 达到限定值;

(8) job_disabled:JOB 被置于DISABLE 状态;

(9) job_chain_stalled:运行于chain 的JOB 被置于CHAIN_STALLED 状态;

(10) job_all_events:含上述提到的所有类型;

(11)job_run_completed:由于Job 运行出错、成功结束或被手动停止。

      起用raise_events 后,Scheduler就会按照设定的触发条件,当达到触发条件时,即会抛出事件信息到SYS.SCHEDULER$_EVENT_QUEUE 队列。


例如,手动执行一次JOBTEST,看看是否向队列中记录信息,操作如下:

SQL> exec dbms_scheduler.run_job('JOBTEST');

PL/SQL procedure successfully completed.

 
执行下列脚本,出队数据:

SQL> set serveroutput on

SQL> DECLARE

l_dequeue_options DBMS_AQ.dequeue_options_t;

l_message_properties DBMS_AQ.message_properties_t;

l_message_handle RAW(16);

l_queue_msg sys.scheduler$_event_info;

BEGIN

l_dequeue_options.consumer_name := 'TEST';

DBMS_AQ.dequeue(queue_name =>'SYS.SCHEDULER$_EVENT_QUEUE',

dequeue_options => l_dequeue_options,

message_properties => l_message_properties,

payload => l_queue_msg,

msgid => l_message_handle);

COMMIT;

DBMS_OUTPUT.put_line('event_type : ' ||l_queue_msg.event_type);

DBMS_OUTPUT.put_line('object_owner : ' ||l_queue_msg.object_owner);

DBMS_OUTPUT.put_line('object_name : ' ||l_queue_msg.object_name);

DBMS_OUTPUT.put_line('event_timestamp: ' ||l_queue_msg.event_timestamp);

DBMS_OUTPUT.put_line('error_code : ' ||l_queue_msg.error_code);

DBMS_OUTPUT.put_line('event_status : ' ||l_queue_msg.event_status);

DBMS_OUTPUT.put_line('log_id : ' || l_queue_msg.log_id);

DBMS_OUTPUT.put_line('run_count : ' ||l_queue_msg.run_count);

DBMS_OUTPUT.put_line('failure_count : ' ||l_queue_msg.failure_count);

DBMS_OUTPUT.put_line('retry_count : ' ||l_queue_msg.retry_count);

END;

/

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:JOBTEST执行一次至少会向队列中插入两条event信息,一条为JOB_STARTED,一条则为JOB_SUCCEEDED(也可能是JOB_FAILED),这里不详细演示,感兴趣的朋友不妨自行测试。

      提示:sys.scheduler$_event_queue 队列基于sys.scheduler$_event_qtab队列表,因此查询sys.scheduler$_event_qtab 也可以获取上述的信息。

      sys.scheduler$_event_queue是一个固定队列,实际应用的过程中,dba 应该根据实际情况,将该表访问权限授予相关用户,以便顺利出队该队列中的events信息。

      默认情况下Scheduler 仅保留最近24 小时的Events信息,如果希望修改该设置的话,可以通过SET_SCHEDULER_ATTRIBUTE 过程,修改scheduler的event_expiry_time 属性,该项属性的属性值以秒为单位。

 
4.2 Application抛出的Events

      Scheduler 能够抛出Events 让外部应用处理,外部的应用也可以抛出Events 让Scheduler 启动job处理,不过并不是任何job 都能够对外部应用抛出的Events 做出响应,必须在创建jobs时明确指定响应的事件。可以通过如下参数指定:

(1)queue_spec:指定外部应用抛出的events消息入队的队列名;

(2)event_condition:指定触发job启动的条件,这一参数的参数值在设置时应当基于事件消息的自身属性,因为事件消息在入队时,消息的属性都是由application定义的,因此在设置触发条件时,也应该根据这些属性值进行设置。

      下面,我们就演示创建一个由event 触发启动的job,具体的操作步骤如下:

SQL> create or replace type Test_type1 asobject

2 (

3 event_type VARCHAR2(10),

4 object_owner VARCHAR2(30),

5 object_name VARCHAR2(30)

6 );

7 /

Type created.

SQL> begin

2 dbms_aqadm.create_queue_table(

3 queue_table => 'my_queue_tbl1',

4 queue_payload_type => 'Test_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.

 
准备工作完成,下面就来创建一个event 触发启动的job,创建脚本如下:

SQL> BEGIN

2 DBMS_SCHEDULER.CREATE_JOB (

3 job_name => 'EVENT_JOB_T1',

4 job_type => 'STORED_PROCEDURE',

5 job_action => 'SYSTEM.IT',

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 仍然执行IT 过程。


      通过pl/sql 直接向event_t1 队列中添加消息的方式,触发job 的启动,具体操作如下。

      (1)首先要执行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.

      (2)执行入队操作:

SQL> declare

v_Message Test_type1;

v_EnqueueOptions dbms_aq.enqueue_options_t;

v_MessageProperties dbms_aq.message_properties_t;

v_msg_handle raw(16);

begin

v_message := jss_type1('OP_SELECT', user, 'tmpObj');

dbms_aq.enqueue(queue_name => 'event_t1',

enqueue_options => v_enqueueOptions,

message_properties => v_messageproperties,

payload => v_message,

msgid => v_msg_handle);

commit;

end;

/

PL/SQL procedure successfully completed.

(3)查询队列表中的数据:

SQL> select user_data from my_queue_tbl1;

USER_DATA(EVENT_TYPE, OBJECT_OWNER, OBJECT_NAME)

---------------------------------------------------------

JSS_TYPE1('OP_SELECT', 'TEST', 'tmpObj')

(4)然后查询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_condition =>'tab.user_data.event_type = ''OP_INSERT''',

      只有当event_type 为'OP_INSERT'时才会触发job 的执行,前面入队时指定的是OP_SELECT,当然没有触发job中指定的procedure ,下面再次执行入队操作:

 

SQL> declare

v_Message jss_type1;

v_EnqueueOptions dbms_aq.enqueue_options_t;

v_MessageProperties dbms_aq.message_properties_t;

v_msg_handle raw(16);

begin

v_message := jss_type1('OP_INSERT', user, 'tmpObj');

dbms_aq.enqueue(queue_name => 'event_t1',

enqueue_options => v_enqueueOptions,

message_properties => v_messageproperties,

payload => v_message,

msgid => v_msg_handle);

commit;

end;

/

再次查看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 doesnot exist 错误。

 
转自:http://blog.csdn.net/tianlesoftware/article/details/4715218
0 0
原创粉丝点击