PL/SQL之--包

一、包

  包是一组相关过程、函数、常量、变量、游标、异常等PL/SQL程序设计元素的组合。它类似于C++和Java中的类,其中变量相当于类中的成员变量,过程和函数相当于类中的方法。通过使用包,可以使开发人员利用面向对象的方法进行存储过程的开发,从而提高系统的性能。

  包的结构如下:

  一个包由包头和包主体组成:

  • 包头(package):包头部分声明包内数据类型、变量、常量、游标、子程序(只有声明)和异常错误处理等元素,这些元素为包的共有元素。
  • 包主体(package body):包主体则是包定义部分的具体实现,它负责为包头中所声明包的私有元素。

  包头和包主体分开编译,并作为两个分开的对象存放在数据库数据字典中。

  包的大体语法如下:

  包头语法:

  CREATE OR REPLACE PACKAGE 包名称 IS
   FUNCTION 函数名称(参数 参数类型) RETURN 参数类型; 
  PROCEDURE 存储过程名称( 参数 输入输出类型 参数类型,参数 输入输出类型 参数类型) ;
  end;

  包体语法:

  create or replace package body 包名称 is
    function 函数名称(参数名称 参数类型) return 参数类型 is
    begin
      处理语句
      return 参数;
    end;
    procedure 存储过程名称( 参数 输入输出类型 参数类型,参数 输入输出类型 参数类型 ) is
    begin
      处理语句;
      commit;
    end;
  end;

二、示例代码

  示例如下:

--包头
CREATE OR REPLACE PACKAGE fkpackage IS
    v_comm NUMBER := 200 ; --每月奖金200
   --定义结构体
  type re_person is record(
      rid person.id%type,
    rusername person.username%type,
    rage person.age%type,
    rpassword person.password%type
  );
    --定义游标
  type t_person is ref cursor;
  --计算年薪的函数
    FUNCTION get_year_sal (v_sal NUMBER) RETURN NUMBER ; --定义过程
    PROCEDURE pro_person_add (
        v_id NUMBER,
        v_username VARCHAR2,
        v_age NUMBER,
        v_password VARCHAR2
    ) ;
  procedure get_person(
    v_id in number,
    c_person out t_person
  );
END fkpackage ;
--包体
create or replace package body fkpackage is
  -- 函数
  function get_year_sal (v_sal NUMBER) RETURN NUMBER IS
  BEGIN
    RETURN (v_sal + v_comm) * 12 ;
  END;
  --过程
   procedure pro_person_add(v_id number, v_username varchar2, v_age number, v_password varchar2) is
  BEGIN
    INSERT INTO person  VALUES (v_id, v_username, v_age, v_password);
    COMMIT;
    END;
  procedure get_person(v_id in number, c_person out t_person) is
    begin 
      open c_person for select id,username,age,password from person;
    end;
 END;

  调用代码:

declare 
    r_person fkpackage.t_person;  --定义包中结构体变量 
    record_person fkpackage.re_person;
    v_id number;
begin  
  --使用及遍历包中过程返回的结果集
  dbms_output.put_line(年薪=||fkpackage.get_year_sal(12000));
  v_id := 1;      
  fkpackage.get_person(v_id, r_person);
   loop
        fetch r_person into record_person;
        exit when r_person%notfound;
        dbms_output.put_line(姓名=||record_person.rage);
    end loop;
    -- 添加数据
    fkpackage.pro_person_add(10001, zhangsan, 20, 1343);
end;

三、 PL/SQL包的优点
包提供了几个优点:模块化、方便应用程序设计、信息隐藏、附加功能和良好的性能。

1、 模块化
  包能让我们把逻辑相关的类型、常量、变量、异常和子程序等放到一个命名的PL/SQL模块中。每一个包都容易理解,包与包之间接口简单、清晰。这将有助于程序开发。

2、 轻松的程序设计 设计应用程序时,我们首先要确定的是包说明中的接口信息。我们可以在没有包体的条件下编写并编译说明部分。然后引用该包的存储子程序也会被编译。在完成整个应用程序之前,我们是不需要完全实现包体部分的。

3、 信息隐藏
  有了包,我们就可以指定哪些类型、常量、变量、异常和子程序等是公有(可见和可访问)或私有(隐藏和不可访问)。例如,如果一个包里包含了四个子程 序,其中三个是公有的一个是私有的。包就会隐藏私有子程序的实现,这样的话,如果实现内容发生改变,受到影响的只有包本身(不是我们的应用程序)。同样, 对用户隐藏实现细节也能保证包的完整性。

4、 附加功能
  打包公有变量和游标在一个会话期会一直存在。所以,它们可以被当前环境下的所有子程序共享。并且它们允许我们跨事务来维护数据而不用把它保存在数据库中。

5、 良好的性能
  在我们首次调用打包子程序时,整个包就会被加载到内存中。所以,以后调用包中的相关子程序时,就不需要再次读取磁盘了。包能阻塞级联依赖,这样就能避免不必要的编译。例如,如果我们改变打包函数的实现,Oracle不需要重新编译调用子程序,因为它们并不依赖于包体。


四、系统中的包
Oracle和各种Oracle工具都提供了系统包来帮助我们建立基于PL/SQL的应用程序。下面介绍一下其中比较典型的包。

1、 关于DBMS_ALERT包
  DBMS_ALERT能让数据库触发器在特定的数据库值发生变化时向应用程序发送报警。报警是基于事务的并且是异步的(也就是它们的操作与定时机制无关)。例如,当新的股票和债券上市时公司就可以通过这个包更新来他的投资总额。

2、 关于DBMS_OUTPUT包
  包DBMS_OUTPUT能让我们显示来自PL/SQL块和子程序中的输出内容,这样就会很容易地进行测试和调试。过程put_line能把信息输 出到SGA的一个缓存中。我们可以通过调用过程get_line或在SQL*Plus中设置SERVEROUTPUT ON就能显示这些信息。

3、 关于DBMS_PIPE包
  包DBMS_PIPE允许不同的会话通过命名管道来进行通信(管道就是一块内存区域,进程使用这个区域把消息传递给另外一个进程)。我们可以使用过 程pack_message和send_message把消息封装到一个管道,然后把消息发送到同一个实例中的另一个会话中。 管道的另一个终端,我们可以使用过程recieve_message和unpack_message来接受并打开要读取的消息。命名管道在很多地方都很有用。例如,我们可以用C语言编写一个收集信息的程序,然后把信息通过管道传递给存储过程。

4、关于UTL_FILE包

  包UTL_FILE能让我们的PL/SQL程序读写操作系统(OS)文本文件。它提供了标准的OS流文件I/O,包括open、put、get和close操作。当我们想要读写文件的时候,我们可以调用函数fopen,它能返回一个在后续过程调用中使用到的文件句柄。例如,过程put_line能往打开的文件中写入文本字符串,并在后边添加一个换行符,过程get_line能从打开的文件读取一行内容到放到一个输出缓存中。

5、关于UTL_HTTP包
  包UTL_HTTP可以让我们PL/SQL程序使用超文本传输协议(HTTP)进行通信。它可以从互联网接收数据或调用Oracle Web服务器的cartridge。这个包有两个入口点,每一个都接受一个URL(统一资源定位器)字符串,然后连接到一个指定的网站并返回所请求的数 据,这些数据通常是超文本标记语言HTML格式。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。