我们正在开发一个 C++ 服务器,它将基于基于时间的事件进行处理。例如,如果特定用户配置了必须在特定时间处理的特定任务,则需要将事件或通知从数据库发送到 C++ 服务器,以启动任务。定时配置存储在数据库中,C++服务器不应该间隔轮询数据库,但应该在配置的定时从数据库通知事件。
我们正在使用 odatabase 和 odynaset 库来连接和访问 oracle 数据库 11g。
请您为上述问题提供解决方案。
我们正在开发一个 C++ 服务器,它将基于基于时间的事件进行处理。例如,如果特定用户配置了必须在特定时间处理的特定任务,则需要将事件或通知从数据库发送到 C++ 服务器,以启动任务。定时配置存储在数据库中,C++服务器不应该间隔轮询数据库,但应该在配置的定时从数据库通知事件。
我们正在使用 odatabase 和 odynaset 库来连接和访问 oracle 数据库 11g。
请您为上述问题提供解决方案。
一种方法是使用Oracle 的 Advanced Queuing。为此,您需要设置一个队列(和一个队列表)并编写一个等待队列中下一条消息的 PL/SQL 过程。
然后,C++ 端调用 PL/SQL 过程,该过程在下一个事件发生时返回。
在 Oracle 方面,您将需要使用DBMS_SCHEDULER或类似工具来创建事件,即在适当的时间将新消息插入队列。
它仍然是一种投票方式。但是,两个事件之间绝对没有活动。
更新:
这是一些示例代码。
队列的初始设置(消息包含一个数字和一个文本值):
grant AQ_ADMINISTRATOR_ROLE to appuser;
grant EXECUTE ON DBMS_AQ to appuser;
grant EXECUTE ON DBMS_AQ to appuser;
CREATE TYPE sample_payload_type AS OBJECT
(
cmd VARCHAR2(20),
id NUMBER
);
BEGIN
DBMS_AQADM.CREATE_QUEUE_TABLE (
queue_table => 'sample_queue_table',
queue_payload_type => 'sample_payload_type',
sort_list => 'ENQ_TIME',
compatible => '10.0'
);
END;
/
BEGIN
DBMS_AQADM.CREATE_QUEUE (
queue_name => 'sample_queue',
queue_table => 'sample_queue_table'
);
DBMS_AQADM.START_QUEUE (
queue_name => 'sample_queue'
);
END;
/
包头:
create or replace package sample_queue_pkg
as
procedure get_next_msg(
i_max_wait number
,o_cmd out varchar2
,o_id out number
);
procedure put_msg(
i_cmd varchar2
,i_id number
);
end sample_queue_pkg;
/
包体:
create or replace package body sample_queue_pkg
as
procedure get_next_msg(
i_max_wait number
,o_cmd out varchar2
,o_id out number
)
is
dequeue_options dbms_aq.dequeue_options_t;
message_properties dbms_aq.message_properties_t;
message_handle RAW(16);
message sample_payload_type;
NO_MESSAGE_RECEIVED EXCEPTION;
PRAGMA EXCEPTION_INIT(NO_MESSAGE_RECEIVED, -25228);
begin
dequeue_options.wait := i_max_wait;
DBMS_AQ.DEQUEUE (
queue_name => 'appuser.sample_queue',
dequeue_options => dequeue_options,
message_properties => message_properties,
payload => message,
msgid => message_handle
);
o_cmd := message.cmd;
o_id := message.id;
exception
when NO_MESSAGE_RECEIVED then
o_cmd := null;
o_id := null;
end get_next_msg;
procedure put_msg(
i_cmd varchar2
,i_id number
)
is
enqueue_options dbms_aq.enqueue_options_t;
message_properties dbms_aq.message_properties_t;
message_handle RAW(16);
message sample_payload_type;
message_id NUMBER;
begin
message := sample_payload_type(i_cmd, i_id);
DBMS_AQ.ENQUEUE(
queue_name => 'appuser.sample_queue',
enqueue_options => enqueue_options,
message_properties => message_properties,
payload => message,
msgid => message_handle
);
end put_msg;
end sample_queue_pkg;
/
数据库服务器可以使用以下代码发送消息:
sample_queue_pkg.put_msg('run_task', 8234);
commit;
C++ 服务器可以等待消息(并接收它们)调用存储的sample_queue_pkg.get_next_msg
. 该参数i_max_wait
指定等待下一条消息的最长时间(以秒为单位)。您可能希望实现一个循环,等待下一条消息并处理它,直到它接收到服务器即将退出的信号。
一种方法是使用 dbms_pipe 或 dbms_alert。即你从你的C++服务器会话连接到数据库(PRO C)并调用dbms_pipe/alert,这将阻塞直到数据库,在另一个会话中将数据发送到c++服务器将读取然后处理的管道。例如,如果它是一个简单的“GO RUN NOW!” 你想发送,那么 dbms_alert 就可以了。
例如:
SQL> declare
2 v_name varchar2(200);
3 v_msg varchar2(200);
4 v_sts number; -- 0 = alert occured, 1 = timeout
5 begin
6 dbms_alert.register('RUN_PROGRAM_A');
7 dbms_alert.register('RUN_PROGRAM_B');
8
9 loop
10 dbms_alert.waitany(v_name,
11 v_msg,
12 v_sts,
13 dbms_alert.maxwait);
14
15 if (v_sts = 0)
16 then
17 dbms_output.put_line('i got alert: ' ||v_name);
18 dbms_output.put_line(' with assoc message: ' ||v_msg);
19 end if;
20 if (v_name = 'RUN_PROGRAM_B')
21 then
22 exit;
23 end if;
24 end loop;
25 end;
26 /
i got alert: RUN_PROGRAM_A
with assoc message: whatever you want to transmit.
i got alert: RUN_PROGRAM_A
with assoc message: whatever you want to transmit.
i got alert: RUN_PROGRAM_B
with assoc message: whatever you want to transmit.
PL/SQL procedure successfully completed.
数据库控制会话在哪里发出这个:
SQL> exec dbms_alert.signal('RUN_PROGRAM_A', 'whatever you want to transmit.');
PL/SQL procedure successfully completed.
SQL> commit;
Commit complete.
SQL> exec dbms_alert.signal('RUN_PROGRAM_A', 'whatever you want to transmit.');
PL/SQL procedure successfully completed.
SQL> commit;
Commit complete.
SQL> exec dbms_alert.signal('RUN_PROGRAM_B', 'whatever you want to transmit.');
PL/SQL procedure successfully completed.
SQL> commit;
Commit complete.
SQL>
另一种方法是调度程序方法dbms_queue
(