0

時間ベースのイベントに基づいて処理するC++サーバーを開発しています。たとえば、特定のユーザーが特定の時間に処理する必要のある特定のタスクを構成した場合、タスクを開始するには、データベースからC++サーバーにイベントまたは通知を送信する必要があります。タイミング構成はデータベースに格納され、C ++サーバーは一定の間隔でデータベースをポーリングするべきではありませんが、構成されたタイミングでデータベースからイベントを通知する必要があります。

Oracleデータベース11gに接続してアクセスするために、odatabaseおよびodynasetライブラリを使用しています。

上記の問題の解決策を提供するようにお願いします。

4

2 に答える 2

2

1つのアプローチは、OracleのAdvancedQueuingを使用することです。そのためには、キュー(およびキュー表)を設定し、キュー内の次のメッセージを待機するPL/SQLプロシージャを作成する必要があります。

次に、C++側はPL/ SQLプロシージャを呼び出します。このプロシージャは、次のイベントが発生したときに戻ります。

Oracle側では、DBMS_SCHEDULERまたは同様の機能を使用してイベントを作成する必要があります。つまり、適切なタイミングで新しいメッセージをキューに挿入する必要があります。

それはまだポーリングアプローチです。ただし、2つのイベントの間にアクティビティはまったくありません。

アップデート:

ここにいくつかのサンプルコードがあります。

キューの初期設定(メッセージには数値とテキスト値が含まれています):

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は、次のメッセージを待機する最大時間を秒単位で指定します。次のメッセージを待機し、サーバーが終了しようとしているというシグナルを受信するまでメッセージを処理するループを実装することをお勧めします。

于 2012-12-03T10:16:51.397 に答える
1

1 つの方法は、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>

もう 1 つのアプローチはスケジューラ アプローチ ( dbms_queue) です。これはメッセージ キュー アプローチであり、キュー テーブルに対してポーリング (デキュー) し、メッセージが到着したときに何かを実行します。

于 2012-12-03T10:27:40.160 に答える