oracle高階佇列在通訊方面的應用設計(AQ高階佇列設計說明一)

itpub120發表於2006-11-23

oracle高階佇列在通訊方面的應用設計

---AQ高階佇列設計說明

關鍵字:佇列,介面,效能

1 前言

一般系統的應用可以分為:立即要執行和可以延遲要執行的事情,區分這個很重要。

為了提高系統的效能,縮短系統等待時間,引入佇列技術。

佇列是一種能將應用程式的處理工作有效地劃分為前臺任務和後臺任務的技術。當處理容量允許時,這種技術透過儲存訊息、確定訊息處理的優先順序和嚮應用程式提交訊息來發揮作用。它使你能夠平衡本地計算機的負荷,或將任務分配到遠端計算機。

為了減少使用者的等待時間,應用程式可以讓說明需要後臺處理的訊息排入佇列。然後就可以從頁面的呈遞過程中去掉該處理任務。由一個後臺程式來讀取並佇列處理這些訊息,或者甚至可以交由一個單獨的系統來處理它們。

佇列可以實現各個系統之間的資料共享,訊息通訊。

2 功能概述

書寫本文的目的:利用oracle高階佇列實現pl/sql程式碼,為其它語言實現高階佇列的功能作介面。

Oracle高階佇列有一下好處:

1 高階佇列管理是Oracle資料庫的一個特性,它提供訊息佇列管理功能。這是一個非常可靠、安全和可伸縮的訊息管理系統,因為它使用與其他基於Oracle技術的應用程式相同的資料庫特性。

2 高階佇列管理的一個很大優點是它可以透過PL/SQLJavaC來訪問,這樣你就可以把來自一個Java servlet的訊息入佇列和使PL/SQL儲存過程中的相同訊息出佇列。

3高階佇列管理的另一個優點是你可以利用這一軟體透過Oracle Net Services (SQL*Net)HTTP(S)SMTP,在遠端節點之間傳播訊息。高階佇列甚至可以透過訊息閘道器與非Oracle的訊息管理系統(如IBM MQSeries)相整合。

4 Oracle高階佇列管理提供了單消費者佇列和多消費者佇列。單消費者佇列只面向單一的接收者。多消費者佇列可以被多個接收者使用。當把訊息放入多消費者佇列時,應用程式的程式設計師必須顯式地在訊息屬性中指定這些接收者,或者建立決定每條訊息的接收者的基於規則的訂閱過程。

佇列的開發主要有:佇列的管理和佇列的操作。

具體開發步驟如下:

1 首先確定應用的需求,是否適合使用高階佇列?使用高階佇列預計提高效能的預期值

2確定佇列包體結構。

3 佇列管理。

4 佇列操作。

2 確定佇列包體結構

底層訊息的通訊oracle已經實現,並且封裝了,現在需要執行訊息包體的結構,訊息的傳送和訊息接收要透過一定的訊息結構完成。

現在以簡訊push為例子,完成高階佇列在簡訊push的應用。

安裝好oracle資料庫後,對smpuser授權

Grant aq_administrator_role To smpuser;

注意:需要把dbms_aq and dbms_aq_admin 包的呼叫功能許可權付給smpuser.

CREATE OR REPLACE Type mt_struc As Object

/*

功能:push 的mt結構,和T_OUTBOX_PUSH結構一致

日期:2006-09-20

write by hancy

*/

(

OP_ID NUMBER ,

DEST_MOBILENO VARCHAR2(32) ,

FEE_MOBILENO VARCHAR2(32) ,

LONG_NO VARCHAR2(21) ,

MT_CONTENT VARCHAR2(500),

SERVICE_ID VARCHAR2(10) ,

MT_FLAG NUMBER(1) ,

MSG_FMT NUMBER(1) ,

FEE_TYPE NUMBER(1) ,

FEE_VALUE NUMBER(4) ,

BEG_REPORT NUMBER(1) ,

CLIENT_ID NUMBER(4) ,

CLIENT_NAME VARCHAR2(10) ,

MT_TIME DATE ,

MT_ID VARCHAR2(40) ,

PLAN_ID NUMBER ,

PUSH_TYPE VARCHAR2(20) ,

SEND_DATE DATE

)

4 佇列管理

4.1建立佇列表

佇列表是佇列的集合,程式碼如下:

建立下行和上行佇列表:

exec dbms_aqadm.create_queue_table(queue_table=>'sms_mt_tab', queue_payload_type=>'mt_struc');

預設:只有一個接收者

具體引數如下:

SQL> desc dbms_aqadm.create_queue_table

Parameter Type Mode Default?

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

QUEUE_TABLE VARCHAR2 IN

QUEUE_PAYLOAD_TYPE VARCHAR2 IN

STORAGE_CLAUSE VARCHAR2 IN Y

SORT_LIST VARCHAR2 IN Y

MULTIPLE_CONSUMERS BOOLEAN IN Y

MESSAGE_GROUPING BINARY_INTEGER IN Y

COMMENT VARCHAR2 IN Y

AUTO_COMMIT BOOLEAN IN Y

PRIMARY_INSTANCE BINARY_INTEGER IN Y

SECONDARY_INSTANCE BINARY_INTEGER IN Y

COMPATIBLE VARCHAR2 IN Y

NON_REPUDIATION BINARY_INTEGER IN Y

SECURE BOOLEAN IN Y

參考dbms_aqadm.create_queue_table
1
.儲存引數storage_clause 可以是 MAXTRANS,LOB
2
sort_list 可以是PRIORITY,enq_time2個引數或者其中一個。具體可以察看對應的 佇列表的資料結構。例如下面的例子
--
建立佇列表,‘sms_aq_tab 佇列表名,' sms_aq_tab '佇列物件名(充當訊息體的物件名稱),以下同
dbms_aqadm.create_queue_table('WDZAQTABLE','WDZAQMSG');
--
建立具有排序功能的佇列表
dbms_aqadm.create_queue_table('WDZSQRTAQTABLE','WDZAQMSG',sort_list => 'PRIORITY,enq_time');
3
。訊息分組引數 message_grouping 可以是 NONE, TRANSACTIONAL
-- message grouping
dbms_aqadm.TRANSACTIONAL CONSTANT BINARY_INTEGER := 1;
dbms_aqadm.NONE CONSTANT BINARY_INTEGER := 0;
後者表示一個與事務相關的訊息分成1組,在提取訊息的時候可以當成一組相關訊息來提取。例如:
--
建立帶帶分組功能的訊息佇列表
dbms_aqadm.create_queue_table('WDZGROUPAQTABLE','WDZAQMSG',
sort_list => 'PRIORITY,enq_time',
message_grouping =>dbms_aqadm.TRANSACTIONAL/*dbms_aqadm.NONE*/ );
4
multiple_consumers表示訊息接受者是否為多個使用者。預設是隻有1個接收者。如果要多個使用者可以接受訊息,需要設定=true
--
建立多個接收者的訊息佇列表
dbms_aqadm.create_queue_table('WDZMUTIAQTABLE','WDZAQMSG',sort_list => 'PRIORITY,enq_time',
message_grouping =>dbms_aqadm.TRANSACTIONAL/*dbms_aqadm.NONE*/
,multiple_consumers => true);

4.2刪除佇列表

Exec dbms_aqadm.drop_queue_table(queue_table => 'sms_mt_tab');
Exec dbms_aqadm.drop_queue_table(queue_table =>
'sms_mo_tab');

4.3建立佇列

建立佇列程式碼如下:

exec dbms_aqadm.create_queue(queue_name=>'sms_mt_queue', queue_table=>'sms_mt_tab');


exec dbms_aqadm.create_queue(queue_name=>'sms_mt_queue_exception', queue_table=>'sms_mt_tab',queue_type=>dbms_aqadm.EXCEPTION_QUEUE);

exec dbms_aqadm.create_queue(queue_name=>'sms_mt_queue_backup', queue_table=>'sms_mt_tab');

引數含義:

參考 dbms_aqadm.create_queue
--
建立佇列, sms_mt_queue為佇列的名稱,' sms_mt_tab ' 佇列表名
dbms_aqadm.create_queue('WDZQUEUE','WDZAQTABLE',queue_type => dbms_aqadm.NORMAL_QUEUE);
引數queue_type 表示佇列是否為正常佇列還是異常佇列,引數值為dbms_aqadm.NORMAL_QUEUE 或者dbms_aqadm.EXCEPTION_QUEUE

--
建立多使用者佇列, 'WDZQUEUE' 為佇列的名稱,'WDZAQTABLE' 佇列表名
dbms_aqadm.create_queue('WDZMUTIQUEUE','WDZMUTIAQTABLE',
queue_type => dbms_aqadm.NORMAL_QUEUE);
--
建立分組佇列, 'WDZGROUPQUEUE' 為佇列的名稱,'WDZAQTABLE' 佇列表名
dbms_aqadm.create_queue('WDZGROUPQUEUE', 'WDZAQTABLE',
queue_type => dbms_aqadm.NORMAL_QUEUE);

4.4刪除佇列

程式碼如下:

Exec dbms_aqadm.drop_queue('sms_mt_queue');

4.5佇列引數調整

A 建立非持久佇列

非持久佇列 顧名思義就是沒有永久儲存到資料的佇列,佇列只存在於系統的記憶體中。

參考 dbms_aqadm.create_np_queue

dbms_aqadm. create_np_queue ('sms_mt_queue', multiple_consumers=>false);

B 啟動一個佇列,' sms_mt_queue ' 為佇列的名稱

dbms_aqadm.start_queue('sms_mt_queue',enqueue=>true, dequeue=> true);

C 停止佇列

引數的意思參考啟動一個佇列

dbms_aqadm.stop_queue(sms_mt_queue ',enqueue=>false, dequeue=>true);

5 佇列操作

說明:

1 入隊

P100_MT_ENQUEUE
(
p_equeue_name In varchar2,
--佇列名單大寫字母,主佇列:SMS_MT_QUEUE 備份佇列:SMS_MT_QUEUE_BACKUP
p_body In t_outbox_push%Rowtype,
--入參,記錄型別,資料來源頭直接呼叫
p_level In Number:=
3, --優先順序別1-5,數值越小越快
p_delay In Number:=
0, --入隊延遲時間,單位:秒
p_res_str OUT VARCHAR2,
--0 成功 其它失敗
p_msg_id OUT Varchar2
--返回的msgid,主鍵
)
2 出佇列

p102_mt_dequeue
(
p_equeue_name In varchar2,
--佇列名單大寫字母,主佇列:SMS_MT_QUEUE 備份佇列:SMS_MT_QUEUE_BACKUP
p_client_id Out Number,
--簡訊內部閘道器
p_res_str Out varchar2,
--返回值 0 成功 -2 佇列為空其它失敗
p_label out varchar2,
--標籤
p_body out varchar2)
--資料包體

3 資料格式轉換 p103_change_label_body_str
(
p_dequeue_body In Mt_Struc,
p_res_str Out Varchar2,
p_label Out varchar2,
p_body Out varchar2
)
/*
功能:把出佇列的字串翻譯成有規則的label,和body
日期:2006-09-20
write by hancy
*/

4 測試入隊

procedure P101_MT_ENQUEUE_TEST
(
p_equeue_name In varchar2,
--佇列名單大寫字母,主佇列:SMS_MT_QUEUE 備份佇列:SMS_MT_QUEUE_BACKUP
p_res_str out Varchar2,
p_msg_id OUT Varchar2
)

5.1入隊

create or replace procedure P100_MT_ENQUEUE
(
p_equeue_name In varchar2,
--佇列名單大寫字母,主佇列:SMS_MT_QUEUE 備份佇列:SMS_MT_QUEUE_BACKUP
p_body In t_outbox_push%Rowtype,
--入參,記錄型別,資料來源頭直接呼叫
p_level In Number:=
3, --優先順序別1-5,數值越小越快
p_delay In Number:=
0, --入隊延遲時間,單位:秒
p_res_str OUT VARCHAR2,
--0 成功 其它失敗
p_msg_id OUT Varchar2
--返回的msgid,主鍵
)
/*
功能:資料來源頭,push,的入隊操作
日期:2006-09-20
write by hancy
*/

Is
v_enqueue_options dbms_aq.enqueue_options_t;
v_message_properties dbms_aq.message_properties_t;
v_message_handle raw(
16);
v_body mt_struc;
---寫日誌區域
vPid NUMBER:=
100;
vProName VARCHAR2(
50):='P100_MT_ENQUEUE';
vProTip VARCHAR2(
255);
vErrorCode VARCHAR2(
20);
vErrorMsg VARCHAR2(
2000);
Begin
--1初始化
p_res_str:=
'-1';

--2 P_BODY 到 v_body 的轉化 把一個字串轉化為一個結構體
v_body:=mt_struc(
p_body.OP_ID ,
p_body.DEST_MOBILENO ,
p_body.FEE_MOBILENO ,
p_body.LONG_NO ,
p_body.MT_CONTENT ,
p_body.SERVICE_ID ,
p_body.MT_FLAG ,
p_body.MSG_FMT ,
p_body.FEE_TYPE ,
p_body.FEE_VALUE ,
p_body.BEG_REPORT ,
p_body.CLIENT_ID ,
p_body.CLIENT_NAME ,
p_body.MT_TIME ,
p_body.MT_ID ,
p_body.PLAN_ID ,
p_body.PUSH_TYPE ,
p_body.SEND_DATE );
--4設定屬性和引數---
--指定異常佇列
v_message_properties.exception_queue:=
'SMS_MT_QUEUE_EXCEPTION';
--設定優先順序別
v_message_properties.priority :=p_level;
--設定延時時間--秒
v_message_properties.delay :=p_delay;
--5 開始入隊
dbms_aqadm.start_queue(p_equeue_name,enqueue=>true, dequeue=> true);
dbms_aq.enqueue(queue_name=>p_equeue_name,
enqueue_options=>v_enqueue_options,
message_properties=>v_message_properties,
payload=>v_body,
msgid=>v_message_handle);
P_MSG_ID:=v_message_handle ;
--6 commit
Commit;
p_res_str:=
'0';
Exception
When Others Then
p_res_str:=
'-100';
vProTip:=
'入隊過程異常!';
vErrorCode:=Sqlcode;
vErrorMsg:=SQLERRM;
p_pub_write_error_log(vPid,vProName,
'','',
vProTip,vErrorCode,vErrorMsg,
1);
Rollback;
end P100_MT_ENQUEUE;

create or replace procedure P101_MT_ENQUEUE_TEST
(
p_equeue_name In varchar2,
--佇列名單大寫字母,主佇列:SMS_MT_QUEUE 備份佇列:SMS_MT_QUEUE_BACKUP
p_res_str out Varchar2,
p_msg_id OUT Varchar2
)
/*
功能:測試入隊
日期:2006-09-20
write by hancy
*/

Is
Cursor cur_push Is
Select * From t_outbox_push;
v_row_push t_outbox_push%Rowtype;
v_exe_res varchar2(
200);
v_message_handle raw(
16);
begin
p_res_str:=
'-1';
Open cur_push;
Loop
Fetch cur_push Into v_row_push;
Exit When cur_push%Notfound;
P100_MT_ENQUEUE(p_equeue_name,v_row_push,
3,0,v_exe_res,v_message_handle);
End Loop;
Close cur_push;
p_res_str:=v_exe_res;
p_msg_id:=v_message_handle;
Exception
When Others Then
p_res_str:=Sqlerrm;
Rollback;
end P101_MT_ENQUEUE_TEST;

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8109090/viewspace-879432/,如需轉載,請註明出處,否則將追究法律責任。

相關文章