Oracle高级队列是实现功能需求的首选机制是什么情况?例如,从理论上讲,从银行账户A转到银行账户B的资金可能被视为两种不同的操作,并且可以单独实施--首先,将资金从账户A(更新)转入队列,然后将资金转移到帐户B(更新)。但是,显然不能这样做,因为这两个操作应该在一个一致的操作- in事务中完成。
也许只有在开发存储过程/函数以执行内部(通过DML操作和调用其他本地存储的proc/fnc)和外部(通过调用某些webservices)的逻辑时,才应该考虑高级队列。当使用这种对we服务的调用时,我们不能将其包装成一致的事务,所以唯一的方法是使用某种排队机制.
任何真实生活中的详细例子都将不胜感激。
我好奇的不是技术本身的细节,而是使用这种消息传递的真实情况,因为我以前没有这样做过。例如,为什么我需要传递一些数据(消息有效载荷)?
发布于 2012-10-02 01:14:04
我用AQ
通过使用队列,您可以执行以下操作:
以下是关于我如何在数据库之间使用AQ的更多信息。我不是专家,大部分代码都是从互联网上得到的。Oracle文档很长,但并没有真正帮助我。
首先创建队列:
BEGIN
SYS.DBMS_AQADM.CREATE_QUEUE_TABLE
(
QUEUE_TABLE => 'QT_NEW_CASE'
,QUEUE_PAYLOAD_TYPE => 'FILE_ACTION'
,COMPATIBLE => '8.1'
,STORAGE_CLAUSE => '
TABLESPACE USERS
PCTUSED 0
PCTFREE 10
INITRANS 1
MAXTRANS 255
STORAGE (
INITIAL 64K
NEXT 1M
MINEXTENTS 1
MAXEXTENTS UNLIMITED
PCTINCREASE 0
BUFFER_POOL DEFAULT
)'
,SORT_LIST => 'ENQ_TIME'
,MULTIPLE_CONSUMERS => FALSE
,MESSAGE_GROUPING => 0
,SECURE => FALSE
);
End;在原始数据库上:
CREATE OR REPLACE TYPE FILE_ACTION AS OBJECT
( ACTION VARCHAR2(20),
CASE_ID NUMBER(10),
OTHER VARCHAR2(20)
);诚然,这一行动是粗糙的,但却是多才多艺的。这些要求是将从多个表到另一个数据库的更改漏斗,在数据库中需要进一步处理,而不需要接触应用程序代码。典型的调用是从触发器、其他过程或作业对包进行调用。
queue_util.add_file ('CLOSE', v_case_id,:NEW.ID);包内
PROCEDURE add_file_to_queue (action_in IN VARCHAR2,
d_case_id_in IN NUMBER,
d_other_in IN VARCHAR2:= NULL)
IS
/******************************************************************************
PURPOSE: when there is a change to a file (create, closed or reopen) add the change to the queue of changes
******************************************************************************/
queue_options SYS.DBMS_AQ.enqueue_options_t;
message_properties SYS.DBMS_AQ.message_properties_t;
message_id RAW (16);
my_message file_action;
err_text VARCHAR2 (2000);
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
my_message := file_action (action_in, d_case_id_in, d_other_in);
DBMS_AQ.enqueue (queue_name => 'NEW_CASE_QUEUE',
enqueue_options => queue_options,
message_properties => message_properties,
payload => my_message,
msgid => message_id);
IF g_debugging
THEN
;
--insert debugging info if g_debugging is true
END IF;
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
err_text := SQLERRM;
--logging error to another table
WHEN OTHERS
THEN
err_text := SQLERRM;
--more logging
END add_file_to_queue;-并将消息从队列中弹出
PROCEDURE send_from queue (case_id_in IN NUMBER := NULL)
IS
/******************************************************************************
PURPOSE:get the list of file changes and send them out
*****************************************************************************/
queue_options DBMS_AQ.dequeue_options_t;
message_properties DBMS_AQ.message_properties_t;
message_id file_action;
v_file VARCHAR2 (20);
v_case_id NUMBER (10);
v_filename VARCHAR2 (500);
v_action VARCHAR2 (20);
v_other VARCHAR2 (20);
v_err_id INTEGER;
bad_data_ex EXCEPTION;
v_err_text VARCHAR2 (50);
TYPE cases_cur IS REF CURSOR;
new_cases cases_cur;
BEGIN
IF case_id_in IS NULL
THEN
OPEN new_cases FOR
SELECT qt.msgid
FROM cqt_new_case qt
ORDER BY qt.enq_time;
ELSE
OPEN new_cases FOR
SELECT qt.msgid
FROM qt_new_case qt
WHERE qt.user_data.case_id = case_id_in
ORDER BY qt.enq_time;
END IF;
--should have added a check here to make sure
--the other database is up and running
LOOP
BEGIN
FETCH new_cases INTO message_id;
--reinitialize values to null
v_case_id := NULL;
v_filename := NULL;
v_file := NULL;
v_action := NULL;
v_other := NULL;
--to try and clear all locks
COMMIT;
EXIT WHEN new_cases%NOTFOUND;
IF case_id_in IS NOT NULL
THEN
queue_options.deq_condition :=
'tab.user_data.case_id = ' || case_id_in;
END IF;
DBMS_AQ.dequeue (queue_name => 'NEW_CASE_QUEUE',
dequeue_options => queue_options,
message_properties => message_properties,
payload => my_message,
msgid => message_id);
v_case_id := my_message.case_id;
v_action := my_message.action;
v_other := my_message.other;
IF v_case_id IS NOT NULL AND v_case_id > 0
THEN
IF g_debugging
THEN
;
--insert your debugging information
END IF;
--continues on with lengthy data transforms
--for actions like NEW, CLOSE, REOPEN
END SEND_FROM_QUEUE;我今天当然会用不同的方式来写,但是它很有效.对于我来说,AQ的关键问题是,我从来没有在不同的数据库之间排队等待消息传递。这被描述为它的一个主要价值。然而,我仍然喜欢确保初始事务可以完成,而不考虑目标数据库的状态。如果在目标数据库中插入消息失败,则会记录错误,并发送电子邮件通知开发人员。
发布于 2012-10-01 02:51:53
我对甲骨文不像对Postgres那么熟悉。尽管如此,我将告诉您这样的排队方法是理想的(作为pg_消息_队列的作者):允许数据库事务具有非事务性的副作用,并且复杂度最小。一个简单的例子是“当我们提交一个事务,说我们已经发送了一个部件,让我们发送一封电子邮件出去通知客户。”
您可以在没有Oracle AQ的情况下做到这一点,但是Oracle AQ可能会使此变得更简单。关键因素是,这允许您对消息进行排队,以便在提交时它是可见的,并且在数据库事务提交而不是之前,消息将作为电子邮件的基础。如果您试图从事务内部发送消息,您将得到一些令人讨厌的失败案例:
另一个例子可能是松散耦合的应用程序,集成在消息队列上。每个应用程序可以在很大程度上不知道另一个应用程序的运行情况,但是当事务被提交时,消息就会发送给另一个应用程序。如果不能马上送到,没问题。我们会在有可能的时候处理它们。
因此,最基本的情况是,在许多情况下,您希望将逻辑集中在数据库周围,在这些情况下,您不能在单个事务中真正正确地完成所有事情。能够在db提交中向其他组件发送消息确实很有帮助。
当然,没有AQ,你可以自己建造一切。但它已经为你建造好了。
编辑:我在这里重读了甲骨文的文档,它们令人绝望地困惑,所以我不怪你在这里的混乱。如果我对他们谈论的事情不太熟悉的话,我就不确定我是否能跟上他们的脚步。我现在百分之百肯定,我的答案是符合目标的。
发布于 2017-01-20 17:58:28
在现实生活中,在数据库中执行特定操作时,可以使用AQ向客户发送通知。
考虑一个用户请求购买一个项目的例子。一旦收到付款,将通过在队列中填充详细信息来创建订单。此队列将有商店所有者和支付消息传递应用程序的订阅者。
因此,订阅者1,即商店所有者(任何要发送给店主的通知)将选择关于要发送的项目的消息。而另一个订户将准备关于购买商品的通知,因此在这种情况下,一旦消息被两个订户处理,订单就被标记为完整,并且队列中的消息被删除。
如果在处理订单过程中出现任何错误,将在异常队列中标记条目,然后可以在稍后处理异常队列消息。
https://dba.stackexchange.com/questions/25161
复制相似问题