基于事件驱动的Oracle作业调度

 

对很多系统而言,作业调度event, 'Scheduler');" target="_self">Scheduler是不可缺少的部分。大数据量集中批量处理、OLAP数据聚集都需要利用业务空闲时段(如夜间)进行处理。Oracle自身提供了较为可靠的运行作业调度器机制,为我们提供了现成的Scheduler组件。

 

调度作业有两种大类型:基于时间(Time-Based)和基于事件(Event-Based)。基于时间的调度作业顾名思义,就是设置特定的时间调度规则。依据时间规则在特定的时间点触发执行代码程序。例如:每天夜间22:00执行数据聚合操作,生成聚合数据。在Oracle中,大部分的作业都是这种类型。比如从10G出现的统计信息收集作业,就是规定在工作日夜间22:00开始进行的基于时间作业。

 

基于事件的作业调度则是依据特定的事件场景。比如:在应用程序发生故障的时候,启动数据清理程序,将中间数据结果还原。这样的作业,调度时间是不确定的,依据具体的业务和程序场景。而且,基于事件作业执行的过程中,要具有作业的特性,也就是作业执行代码执行和触发作业程序之间是异步执行关系。

 

在Oracle中,我们可以方便的时候dbms_scheduler包进行基于时间作业的定义。同样,我们可以借助Oracle消息队列的特性,来实现Event Based作业类型。

 

1、原理和环境准备

 

为了更好说明问题,笔者选择Oracle 10R2作为实验环境,并且构建一个新的用户schema环境。

 

 

SQL> show user;

User is "SYS"

 

SQL> select * from v$version;

 

BANNER

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

Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod

PL/SQL Release 10.2.0.1.0 - Production

CORE   10.2.0.1.0   Production

 

TNS for 32-bit Windows: Version 10.2.0.1.0 - Production

NLSRTL Version 10.2.0.1.0Production

 

 

创建一个新用户testuser,并授予相应的系统和角色权限。

 

 

SQL> create user testuser identified by testuser ;

User created

 

SQL> alter user testuser quota unlimited on users;

User altered

 

SQL> grant connect to testuser;

Grant succeeded

 

SQL> grant create table to testuser;

Grant succeeded

 

SQL> grant create sequence to testuser;

Grant succeeded

 

SQL> grant create type to testuser;

Grant succeeded

 

SQL> GRANTAQ_ADMINISTRATOR_ROLETO testuser;

Grant succeeded

 

SQL> GRANT CREATE JOB TO testuser;

Grant succeeded

 

 

只有设置了AQ_ADMINISTRATOR_ROLE角色,才能使用Oracle的Advanced Queue组件功能。

 

原理上:我们要利用Oracle的Advanced Queue组件的功能。要求在特定的Event发生时,我们需要向队列中传入一个标记对象。Scheduler会根据特定的标记对象标识来调用特定的作业Job代码程序。这样就实现了基本的Event Based Job。

 

2、日志插入作业

 

我们希望实现一个功能,就是在特定事件发生的时候,会向数据表中插入一条记录。

 

首先,我们准备代码数据表。

 

 

SQL> conn testuser/testuser@ots;

Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.1.0

Connected as testuser

 

 

SQL> create sequence seq_test;

Sequence created

 

SQL> create table test_log (id number not null, comments varchar2(100), created date);

Table created

 

SQL> alter table test_log add constraint pk_test primary key (id);

Table altered

 

 

我们创建了日志数据表。当触发事件的时候,直接向该数据表中插入一条记录。

 

3、配置调度作业

 

首先,需要定义一个类型type,用于向AQ中触发作业。该type相当于事件发生的信息单元。

 

 

SQL> create or replace type t_event_que_payload as object (event_name varchar2(30));

 2 /

Type created

 

 

创建事件表,用来记录消息队列AQ中消息信息。

 

 

SQL> exec dbms_aqadm.create_queue_table(queue_table => 'event_queue_table',queue_payload_type => 't_event_que_payload',multiple_consumers => true,comment => 'Test Event Queue');

 

PL/SQL procedure successfully completed

 

 

使用dbms_aqadm方法create_queue_table中,两个最重要的参数:queue_table是创建消息表的名称,queue_payload_type则是规定了队列中存放对象的type类型。

 

执行后,的确创建了数据表event_queue_table。

 

 

SQL> desc event_queue_table;

Name             Type               Nullable Default Comments

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

Q_NAME           VARCHAR2(30)       Y                        

MSGID            RAW(16)                                      

CORRID           VARCHAR2(128)      Y                        

PRIORITY         NUMBER             Y         

(篇幅原因,有省略……

 

 

下面需要创建队列对象,单独执行出队列名称和队列数据表名称。

 

 

SQL> exec dbms_aqadm.create_queue(queue_name => 'event_queue',queue_table => 'event_queue_table');

PL/SQL procedure successfully completed

 

 

SQL> select name, queue_table, qid, queue_type,user_comment from user_queues;

 

NAME                          QUEUE_TABLE                          QID QUEUE_TYPE          USER_COMMENT

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

EVENT_QUEUE                   EVENT_QUEUE_TABLE                 111623 NORMAL_QUEUE        

AQ$_EVENT_QUEUE_TABLE_E       EVENT_QUEUE_TABLE                 111622 EXCEPTION_QUEUE     exception queue

 

 

 

 

注意,为了队列AQ,Oracle要创建出多个数据表,用于进行不同的消息存储。同时,处于性能等多方面的考量,很多这样的数据表是采用IOT(Index-Organized Table)结构的。

 

 

SQL> select table_name, tablespace_name, iot_name,iot_type from user_tables;

 

TABLE_NAME                    TABLESPACE_NAME        IOT_NAME IOT_TYPE

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

TEST_LOG                      USERS                                                        

EVENT_QUEUE_TABLE             USERS                                                        

AQ$_EVENT_QUEUE_TABLE_S       USERS                                                        

SYS_IOT_OVER_111613           USERS        AQ$_EVENT_QUEUE_TABLE_G       IOT_OVERFLOW

AQ$_EVENT_QUEUE_TABLE_I                                             IOT

AQ$_EVENT_QUEUE_TABLE_G                                             IOT

AQ$_EVENT_QUEUE_TABLE_H                                             IOT

AQ$_EVENT_QUEUE_TABLE_T                                             IOT

 

8 rows selected

 

 

最后,启动创建出的AQ队列event_queue。

 

 

SQL> EXEC DBMS_AQADM.start_queue (queue_name => 'event_queue');

PL/SQL procedure successfully completed

 

 

注意,此时队列状态开启为可用。

 

 

SQL> select name, queue_table, qid, queue_type,ENQUEUE_ENABLED, DEQUEUE_ENABLED from user_queues;

 

NAME                  QUEUE_TABLE         QID QUEUE_TYPE          ENQUEUE_ENABLED DEQUEUE_ENABLED

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

EVENT_QUEUE            EVENT_QUEUE_TABLE  111623 NORMAL_QUEUE          YES            YES

AQ$_EVENT_QUEUE_TABLE_E EVENT_QUEUE_TABLE 111622 EXCEPTION_QUEUE       NO             NO

 

 

队列创建到此结束。下面创建作业,使用dbms_scheduler方法。

 

 

SQL> begin

 2    dbms_scheduler.create_job(job_name => 'event_based_job',

 3                              job_type => 'PLSQL_BLOCK',

 4                              job_action => 'begin

 5                                insert into test_log values (seq_test.nextval, ''TT'', sysdate);

 6                                commit;

 7                              end;

 8                              ',

 9                              start_date=>systimestamp,

 10                              event_condition => 'tab.user_data.event_name = ''test_signal''',

 11                              queue_spec => 'event_queue',

 12                              enabled => TRUE);

 13 end;

 14 /

 

PL/SQL procedure successfully completed

 

SQL> select job_name, job_creator from user_scheduler_jobs;

 

JOB_NAME                      JOB_CREATOR

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

EVENT_BASED_JOB               TESTUSER

 

 

注意包方法的几个主要参数。Job_name定义了新增加job的名称。Job_action定义了当这个Job被触发的时候,需要执行哪段代码。Event_condition规定了调度数据对象值为test_signal的时候才会执行这个作业。Queue_spec制定了监视事件的队列名称。

 

4、测试作业情况

 

我们模拟向队列中插入事件消息对象的场景。

 

 

SQL> DECLARE

 2   l_enqueue_options   DBMS_AQ.enqueue_options_t;

 3   l_message_properties DBMS_AQ.message_properties_t;

 4   l_message_handle    RAW(16);

 5   l_queue_msg         t_event_que_payload;

 6 BEGIN

 7   l_queue_msg :=t_event_que_payload('test_signal'); --创建事件event消息对象;

 8 

 9   DBMS_AQ.enqueue(queue_name        =>'event_queue',

 10                   enqueue_options   => l_enqueue_options,

 11                   message_properties => l_message_properties,

 12                   payload           =>l_queue_msg,

 13                   msgid             => l_message_handle);

 14   COMMIT;

 15 END;

 16 /

 

PL/SQL procedure successfully completed

 

 

在实际使用的时候,只需要向AQ队列中插入消息体。Oracle就可以根据消息的内容调用特定的作业。观察结果:

 

--作业效果;

SQL> select * from test_log;

 

       ID COMMENTS  CREATED

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

        1 TT        2012/1/29 1

 

--作业执行记录;

SQL> col job_name for a20;

SQL> select log_date, job_name, job_class, status from user_scheduler_job_log;

 

LOG_DATE            JOB_NAME            JOB_CLASS                     STATUS

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

29-1月 -12 01.43.47. EVENT_BASED_JOB     DEFAULT_JOB_CLASS             SUCCEEDED

484000 下午 +08:00                                                      

 

 

 

5、结论

 

event_based作业类型,在实际中出现的机率并不是很高。主要是一些数据现场恢复和清理工作。使用Oracle的AQ和调度器机制,我们可以方便的将这种类型作业加以实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值