将持久消息与存储在云对象存储中的消息一起使用

DBMS_PIPE 程序包在自治 AI 数据库上具有扩展功能,可支持持久性消息传递,其中消息存储在云对象存储中。

关于使用 DBMS_PIPE 进行持久消息传递

通过使用 DBMS_PIPE 进行持久消息传递,一个或多个数据库会话可以在同一区域或跨区域与存储在云对象存储中的消息进行通信。

DBMS_PIPE 中的持久消息:

可以在任何支持的 DBMS_PIPE 类型中创建持久性消息传递管道:

注:Oracle 建议在发送或接收具有持久性消息传送的消息之前创建显式管道。使用 DBMS_PIPE.CREATE_PIPE 创建显式管道可确保使用所需的访问权限(公共或专用)(通过设置 private 参数)创建管道。

下面显示了具有持久性消息传送的 DBMS_PIPE 的常规工作流:

插图 database-pipe-persistent-messaging.svg 的说明

使用 DBMS_PIPE 的现有应用程序可以在极少更改的情况下继续运行。您可以使用登录触发器或使用其他一些初始化例程,为使用 DBMS_PIPE 的现有应用程序配置凭证对象和位置 URI。设置 DBMS_PIPE 身份证明和位置 URI 后,无需进行任何其他更改即可使用持久性消息传送。所有后续使用管道都将消息存储在云对象存储中,而不是存储在数据库内存中。这样,您可以将消息的存储方法从内存中更改为持久性云对象存储,且只需进行少量更改。

持久消息传递概述和功能

使用持久消息传递的 DBMS_PIPE 功能:

DBMS_PIPE 权限授权和安全

DBMS_PIPE 过程在调用者的权限下运行。专用管道归当前用户所有,由用户创建的专用管道只能由同一用户使用。这适用于将消息存储到云对象存储的内存中管道和持久性消息传递管道。发送和接收消息在调用者的方案中运行。

使用将消息存储到云对象存储的专用管道,需要身份证明对象才能使用 location_uri 参数标识的云对象存储进行验证。调用用户必须对使用用于访问对象存储的 credential_name 参数指定的身份证明对象具有 EXECUTE 权限。

要使用公共管道,用户、数据库会话必须对 DBMS_PIPE 具有执行权限。对于使用持久消息传送并将消息存储到云对象存储的公共管道,用户、数据库会话必须对 DBMS_CLOUD 具有执行权限并对身份证明对象执行权限(或者您可以创建允许访问包含消息的位置 URI 的身份证明对象)。

DBMS_PIPE 限制

DBMS_PIPE 软件包不支持在使用不同字符集的数据库之间发送消息。例如,如果您有一个使用 AL32UTF8 的自治 AI 数据库实例和另一个使用 WE8MSWIN1252 的实例,则无法在这两个数据库之间发送带有 DBMS_PIPE 的消息。在这种情况下,如果尝试在这两个数据库之间发送带有 DBMS_PIPE 的消息,系统将引发错误 ORA-12704

有关详细信息,请参阅自治 AI 数据库的字符集选择

创建显式持久性管道并发送消息

描述创建具有指定管道名称(显式管道)的持久性管道的步骤。

  1. 使用过程 DBMS_CLOUD.CREATE_CREDENTIAL 存储对象存储身份证明。例如:

    BEGIN
      DBMS_CLOUD.CREATE_CREDENTIAL(
        credential_name => 'my_persistent_pipe_cred',
        username => 'adb_user@example.com',
        password => 'password'
      );
    END;
    /

    此操作以加密格式将身份证明存储在数据库中。可以将任何名称用于身份证明名称。请注意,除非对象存储身份证明发生更改,否则此步骤仅需要一次。存储身份证明后,您可以使用相同的身份证明名称访问云对象存储以使用 DBMS_PIPE 发送和接收消息。

    有关参数的详细信息,请参见 CREATE_CREDENTIAL Procedure 。对于 Oracle Cloud Infrastructure Object Storage,身份证明需要使用原生 Oracle Cloud Infrastructure 验证。

    注:一些工具(如 SQL*Plus 和 SQL Developer)使用 & 符号 (&) 作为特殊字符。如果口令中有 & 符号,请使用示例中所示的这些工具中的 SET DEFINE OFF 命令禁用特殊字符并正确创建身份证明。

  2. 创建显式管道以发送和检索消息。例如,创建一个名为 ORDER_PIPE 的管道。

    DECLARE
      r_status INTEGER;
    BEGIN
        r_status := DBMS_PIPE.CREATE_PIPE(pipename => 'ORDER_PIPE');
    END;
    /

    有关更多信息,请参见 CREATE_PIPE Function

  3. 检验是否创建了管道。

    SELECT ownerid, name, type FROM v$db_pipes
           WHERE name = 'ORDER_PIPE';
    OWNERID NAME       TYPE
    
    ------- ---------- -------
        80 ORDER_PIPE PRIVATE
  4. 使用 DBMS_PIPE 过程设置默认访问身份证明和位置 URI,以将持久性消息存储到云对象存储。

    BEGIN
        DBMS_PIPE.SET_CREDENTIAL_NAME('my_persistent_pipe_cred');
        DBMS_PIPE.SET_LOCATION_URI('https://objectstorage.us-phoenix-1.oraclecloud.com/n/namespace-string/b/bucketname1/');
    END;
    /

    这些过程设置用于 DBMS_PIPE 过程的缺省身份证明名称和缺省位置 URI。

    如果您使用 Oracle Cloud Infrastructure Object Storage 来存储消息,则可以使用 Oracle Cloud Infrastructure Native URI 或 Swift URI。但是,位置 URI 和身份证明在类型中必须匹配,如下所示:

    • 如果您使用本机 URI 格式来访问 Oracle Cloud Infrastructure Object Storage,则必须在身份证明对象中使用本机 Oracle Cloud Infrastructure 签名密钥验证。

    • 如果使用 Swift URI 格式访问 Oracle Cloud Infrastructure Object Storage,则必须在身份证明对象中使用验证令牌验证。

    有关更多信息,请参见 SET_CREDENTIAL_NAME ProcedureGET_LOCATION_URI Function

  5. 在管道上打包并发送消息。

    DECLARE
      l_result INTEGER;
      l_date   DATE;
    BEGIN
        l_date := sysdate;
        DBMS_PIPE.PACK_MESSAGE(l_date);         -- date of order
        DBMS_PIPE.PACK_MESSAGE('C123');         -- order number
        DBMS_PIPE.PACK_MESSAGE(5);              -- number of items in order
        DBMS_PIPE.PACK_MESSAGE('Printers');     -- type of item in order
    
    
        l_result := DBMS_PIPE.SEND_MESSAGE(
                        pipename => 'ORDER_PIPE',
                        credential_name => DBMS_PIPE.GET_CREDENTIAL_NAME,
                        location_uri => DBMS_PIPE.GET_LOCATION_URI);
    
        IF l_result = 0 THEN
            DBMS_OUTPUT.put_line('DBMS_PIPE sent order successfully');
        END IF;
    
    END;
    /

    有关详细信息,请参阅 Oracle Database 19c PL/SQL Packages and Types ReferenceOracle Database 26ai PL/SQL Packages and Types ReferenceSEND_MESSAGE Function 中的 PACK_MESSAGE Procedures

在同一数据库上检索持久消息

介绍从同一自治 AI 数据库实例(发送消息的实例)上的显式管道检索持久性消息的步骤。

在自治 AI 数据库实例上,您可以从其他会话接收发送到管道的消息。DBMS_PIPE 过程是调用的权限过程,并以当前调用的用户的身份运行。

专用管道由创建管道的当前用户拥有。专用管道只能由创建管道的同一用户访问。这适用于使用内存中消息的管道以及使用持久性消息传送来处理存储在云对象存储中的消息的管道。

DBMS_PIPE 具有执行权限的任何数据库会话都可以访问公共管道。这适用于使用内存中消息的管道以及使用持久性消息传送来处理存储在云对象存储中的消息的管道。

  1. 检验是否创建了管道。

    SELECT ownerid, name, type FROM v$db_pipes
           WHERE name = 'ORDER_PIPE';
    OWNERID NAME       TYPE
    
    ------- ---------- -------
        80 ORDER_PIPE PRIVATE

    如果您位于同一自治 AI 数据库实例上并且存在管道,则无需在收到消息之前运行 DBMS_PIPE.CREATE_PIPE。这适用于在同一实例上创建管道的情况,如 Create an Explicit Persistent Pipe and Send a Message 中所示。

  2. 从管道接收消息。

    DECLARE
        message1  DATE;
        message2  VARCHAR2(100);
        message3  INTEGER;
        message4  VARCHAR2(100);
        l_result  INTEGER;
    
    BEGIN
    
        DBMS_PIPE.SET_CREDENTIAL_NAME('my_persistent_pipe_cred');
        DBMS_PIPE.SET_LOCATION_URI('https://objectstorage.us-phoenix-1.oraclecloud.com/n/namespace-string/b/bucketname1/');
        l_result := DBMS_PIPE.RECEIVE_MESSAGE (
                      pipename => 'ORDER_PIPE',
                      timeout  => DBMS_PIPE.MAXWAIT,
                      credential_name => DBMS_PIPE.GET_CREDENTIAL_NAME,
                      location_uri => DBMS_PIPE.GET_LOCATION_URI);
    
        IF l_result = 0 THEN
            DBMS_PIPE.unpack_message(message1);
            DBMS_PIPE.unpack_message(message2);
            DBMS_PIPE.unpack_message(message3);
            DBMS_PIPE.unpack_message(message4);
    
            DBMS_OUTPUT.put_line('Order Received Successfully On: ' || TO_CHAR(sysdate, 'dd-mm-yyyy hh24:mi:ss'));
            DBMS_OUTPUT.put_line('Date of Order: ' || message1);
            DBMS_OUTPUT.put_line('Order Number: ' || message2);
            DBMS_OUTPUT.put_line('Number of Items In Order: ' || message3);
            DBMS_OUTPUT.put_line('Item Type in Order: ' || message4);
        END IF;
    
    END;
    /

    当您在同一自治 AI 数据库实例上时,身份证明已存在,您无需运行 DBMS_CLOUD.CREATE_CREDENTIAL 即可接收消息。这适用于在同一实例上创建管道的情况,如 Create an Explicit Persistent Pipe and Send a Message 中所示。

有关更多信息,请参见 SET_CREDENTIAL_NAME ProcedureGET_LOCATION_URI Function

有关更多信息,请参见 RECEIVE_MESSAGE Function

通过在其他数据库上创建管道来检索持久消息

介绍检索云对象存储中存储的持久性消息的步骤,该持久性消息使用与发送消息的实例不同的自治 AI 数据库实例的显式管道。

  1. 使用过程 DBMS_CLOUD.CREATE_CREDENTIAL 存储对象存储身份证明。例如:

    BEGIN
      DBMS_CLOUD.CREATE_CREDENTIAL(
        credential_name => 'my_persistent_pipe_cred',
        username => 'adb_user@example.com',
        password => 'password'
      );
    END;
    /

    此操作以加密格式将身份证明存储在数据库中。可以将任何名称用于身份证明名称。请注意,除非对象存储身份证明发生更改,否则此步骤仅需要一次。存储身份证明后,您可以使用相同的身份证明名称访问云对象存储以使用 DBMS_PIPE 发送和接收消息。

    有关参数的详细信息,请参见 CREATE_CREDENTIAL Procedure

    注:一些工具(如 SQL*Plus 和 SQL Developer)使用 & 符号 (&) 作为特殊字符。如果口令中有 & 符号,请使用示例中所示工具中的 SET DEFINE OFF 命令禁用特殊字符并正确创建身份证明。

  2. 创建一个与发送消息的管道同名的显式管道。例如,创建一个名为 ORDER_PIPE 的管道。

    DECLARE
      r_status INTEGER;
    BEGIN
        r_status := DBMS_PIPE.CREATE_PIPE(pipename => 'ORDER_PIPE');
    END;
    /

    请参见 CREATE_PIPE Function

  3. 检验是否创建了管道。

    SELECT ownerid, name, type FROM v$db_pipes
           WHERE name = 'ORDER_PIPE';
    OWNERID NAME       TYPE
    
    ------- ---------- -------
        80 ORDER_PIPE PRIVATE
  4. 使用 DBMS_PIPE 过程为对象存储设置默认访问身份证明和位置 URI,以便 DBMS_PIPE 可以访问持久性消息。

    BEGIN
        DBMS_PIPE.SET_CREDENTIAL_NAME('my_persistent_pipe_cred');
        DBMS_PIPE.SET_LOCATION_URI('https://objectstorage.us-phoenix-1.oraclecloud.com/n/namespace-string/b/bucketname1/');
    END;
    /

    这些过程设置用于 DBMS_PIPE 过程的缺省身份证明名称和缺省位置 URI。

    如果您使用 Oracle Cloud Infrastructure Object Storage 来存储消息,则可以使用 Oracle Cloud Infrastructure Native URI 或 Swift URI。但是,位置 URI 和身份证明在类型中必须匹配,如下所示:

    • 如果您使用本机 URI 格式来访问 Oracle Cloud Infrastructure Object Storage,则必须在身份证明对象中使用本机 Oracle Cloud Infrastructure 签名密钥验证。

    • 如果使用 Swift URI 格式访问 Oracle Cloud Infrastructure Object Storage,则必须在身份证明对象中使用验证令牌验证。

    有关更多信息,请参见 SET_CREDENTIAL_NAME ProcedureGET_LOCATION_URI Function

  5. 从持久性管道接收消息。

    DECLARE
        message1  DATE;
        message2  VARCHAR2(100);
        message3  INTEGER;
        message4  VARCHAR2(100);
        l_result  INTEGER;
    
    BEGIN
    
        DBMS_PIPE.SET_CREDENTIAL_NAME('my_persistent_pipe_cred');
        DBMS_PIPE.SET_LOCATION_URI('https://objectstorage.us-phoenix-1.oraclecloud.com/n/namespace-string/b/bucketname1/');
        l_result := DBMS_PIPE.RECEIVE_MESSAGE (
                      pipename => 'ORDER_PIPE',
                      timeout  => DBMS_PIPE.MAXWAIT,
                      credential_name => DBMS_PIPE.GET_CREDENTIAL_NAME,
                      location_uri => DBMS_PIPE.GET_LOCATION_URI);
    
        IF l_result = 0 THEN
            DBMS_PIPE.unpack_message(message1);
            DBMS_PIPE.unpack_message(message2);
            DBMS_PIPE.unpack_message(message3);
            DBMS_PIPE.unpack_message(message4);
    
            DBMS_OUTPUT.put_line('Order Received Successfully On: ' || TO_CHAR(sysdate, 'dd-mm-yyyy hh24:mi:ss'));
            DBMS_OUTPUT.put_line('Date of Order: ' || message1);
            DBMS_OUTPUT.put_line('Order Number: ' || message2);
            DBMS_OUTPUT.put_line('Number of Items In Order: ' || message3);
            DBMS_OUTPUT.put_line('Item Type in Order: ' || message4);
        END IF;
    
    END;
    /

    有关更多信息,请参见 RECEIVE_MESSAGE Function

删除持久性管道

描述删除持久性管道的步骤。

持久管道通过在云对象存储中存储消息来发送和接收消息。使用 DBMS_PIPE.REMOVE_PIPE 删除自治 AI 数据库实例上的持久性管道。

  1. 调用 DBMS_PIPE.REMOVE_PIPE 函数以删除管道。

    DECLARE
       l_result  INTEGER;
    BEGIN
         l_result := DBMS_PIPE.REMOVE_PIPE('ORDER_PIPE');
    END;
    /

    REMOVE_PIPE 函数从运行该管道的自治 AI 数据库实例中删除管道,但是 REMOVE_PIPE 不会影响具有使用相同位置 URI 的相同名称管道的其他自治 AI 数据库实例。

  2. 在您运行 DBMS_PIPE.REMOVE_PIPE 的自治 AI 数据库实例上,验证是否已删除管道。

    SELECT ownerid, name, type FROM v$db_pipes
           WHERE name = 'ORDER_PIPE';
    No rows selected