zoukankan      html  css  js  c++  java
  • [PLSQL]DBMS_PIPE at a glance

    扯在前面

    之前提到过Advanced Queue可以用来多个session之间的信息传递,AQ本质上还是依赖于queue table。DBMS_PIPE也可以用来做inter-session的信息传递,但是比较AQ来说,个人感觉还是相当轻量级的。DBMS_PIPE顾名思义,提供像pipe的功能,跟AQ比较起来,数据都是存在内存里面的,因此持久性不强,另外也不提供callback方式来读取信息。

    通过DBMS_PIPE发送接收信息的大概流程如下:信息发送方首先在自己当前session的UGA中打包(pack)要传递的信息,完了之后,通过“指定”的pipe将数据send到SGA中,这样其他session就可以通过相同的pipe连接到SGA中的区域将数据“打包”地取回到自己session的UGA中,然后解包(unpack)读取其中的数据信息。

    DBMS_PIPE相关接口

    DBMS_PIPE主要提供如下一些程序接口,

    - CREATE_PIPE function (necessary for private pipes)

    - REMOVE_PIPE function

    - PACK_MESSAGE procedure   (builds message in local buffer)

    - UNPACK_MESSAGE procedure ( accesses next item in buffer)

    - SEND_MESSAGE function  (sends message on named pipe: this implicitly creates a public pipe if the named pipe does not exist)

    - UNIQUE_SESSION_NAME function  (returns unique session name)

    - PURGE procedure (purges contents of named pipe)

    有一点要特别注意的是, pipe根据访问权限可以分为public pipeprivate pipe, 根据创建方式又可以分为explicit pipeimplicit pipe.

    - implicit pipe (通过SEND_MESSAGE创建)都是 public pipe. 如果要创建private pipe,必须通过PACK_PIPE.create_pipe来创建。

    - implicit pipe 当pipe空的时候会自行消失

    - explicit pipe 必须通过pack_pipe.remove_pipe来删除

    - public pipe 可以被所有对dbms_pipe拥有execute权限的user访问

    - private pipe 只能够被该pipe创建者的session来访问或者是拥有sysdba权限的用户。

    DBMS_PIPE in Action

    首先看看如何显示地创建public/private pipe, 可以通过视图v$db_pipes 来查看创建的pipe,注意到public pipe的ownerid 的空的。

    必须通过dbms_pipe.remove_pipe来删除显示创建的pipe.


    1 declare
    2 l_result integer;
    3 begin
    4 l_result := dbms_pipe.create_pipe(pipename=> 'explicit_public_pipe', private=> false);
    5 l_result := dbms_pipe.create_pipe(pipename=> 'explicit_private_pipe');
    6* end;
    7 /

    PL
    /SQL procedure successfully completed.

    SQL
    > col name for a30
    SQL
    > select * from v$db_pipes;

    OWNERID NAME TYPE PIPE_SIZE
    ---------- ------------------------------ ------- ----------
    292 EXPLICIT_PRIVATE_PIPE PRIVATE 1430
    EXPLICIT_PUBLIC_PIPE
    PUBLIC 1429

    SQL
    > declare
    2 l_result integer;
    3 begin
    4 l_result := dbms_pipe.remove_pipe(pipename=>'explicit_public_pipe');
    5 l_result := dbms_pipe.remove_pipe(pipename=>'explicit_private_pipe');
    6 end;
    7 /

    PL
    /SQL procedure successfully completed.

    SQL
    > select * from v$db_pipes;

    no rows selected

    SQL
    >

    接下来看一个package, 里面包含了send/receive message的调用接口。因为pipe中的message是通过dbms_pipe.pack_message来一点一点打包的,而接收方必须按照相同的方式来一点一点unpack这个message,如果只是提供send接口,那么接收方很难知道怎么去读取pipe中的信息,很容易出错。因此同时提供send/receive的实现是一个很好的idea.

    SQL> create or replace package message_api as
    2 procedure send(vv_number in number,
    3 vv_text in varchar2,
    4 vv_date in date default sysdate);
    5 procedure receive;
    6 end message_api;
    7 /

    Package created.
    1 create or replace package body message_api as
    2 procedure send(vv_number in number,
    3 vv_text in varchar2,
    4 vv_date in date default sysdate)
    5 as
    6 v_status number;
    7 begin
    8 dbms_pipe.pack_message(vv_number);
    9 dbms_pipe.pack_message(vv_text);
    10 dbms_pipe.pack_message(vv_date);
    11 v_status := dbms_pipe.send_message('message_pipe');
    12 if v_status != 0 then
    13 raise_application_error(-20001, 'message_pipe error');
    14 end if;
    15 end;
    16 procedure receive as
    17 v_result integer;
    18 v_number number;
    19 v_text varchar2(32767);
    20 v_date date;
    21 begin
    22 v_result := dbms_pipe.receive_message
    23 ( pipename => 'message_pipe',
    24 timeout => dbms_pipe.maxwait);
    25 if v_result = 0 then
    26 dbms_pipe.unpack_message(v_number);
    27 dbms_pipe.unpack_message(v_text);
    28 dbms_pipe.unpack_message(v_date);
    29 dbms_output.put_line('v_number: ' || v_number);
    30 dbms_output.put_line('v_text: ' || v_text);
    31 dbms_output.put_line('v_date: ' || v_date);
    32 else
    33 raise_application_error(-20002, 'message_api.receive was unsuccessful');
    34 end if;
    35 end receive;
    36* end message_api;
    SQL
    > /

    Package body created.

    接下来进行简单的测试一下....

    在session 1中调用send接口,往pipe里面send一条message,

    SQL> begin
    2 message_api.send(vv_number => 11111, vv_text=> 'Test', vv_date=> sysdate);
    3 end;
    4 /

    PL
    /SQL procedure successfully completed.

    在session 2中调用receive接口来接收message,

    SQL> exec message_api.receive;
    v_number:
    11111
    v_text: Test
    v_date:
    06-NOV-10

    PL
    /SQL procedure successfully completed.

    两个session哪个先启动无所谓,不过要注意的是receive的时候如果发现pipe里面没有message会进行等待 (session is hanging)

    另外如果send了多条message,同样也要通过多次receive来获取全部的message。

    说明

    本文的例子来源 http://www.oracle-base.com/articles/misc/dbms_pipe.php




    --------------------------------------
    Regards,
    FangwenYu
  • 相关阅读:
    RBAC权限管理模型 产品经理 设计
    Redisson 分布式锁
    Jenkins下载历史Build版本的归档文件
    Java JPA @Transient 在Hibernate中应用
    Solving the Top ERP and CRM Metadata Challenges with erwin & Silwood
    MySQL 字符串 分割 多列
    MySQL CONCAT opposite
    Web并发页面访问量统计实现
    UNIX网络编程读书笔记:基本UDP套接口编程
    UNIX网络编程调试工具:tcpdump、netstat和lsof
  • 原文地址:https://www.cnblogs.com/fangwenyu/p/1870665.html
Copyright © 2011-2022 走看看