所谓包, 就是把一组PL/SQL 的代码元素组织在一个命名空间下.

另外, 包的用法就类似java中的类.( 有封装, 有重载, 没有继承和多肽)

 create or replace procedure process_employee(
employee_id_in IN employees.employee_id%type)
is
l_full_name varchar2(100);
begin
select last_name || ' , ' || first_name
into l_full_name
from employees
where employee_id = employee_id_in;
dbms_output.put_line('The full name is : ' || l_full_name);
end;
/
show errors; -- 运行1
begin
process_employee(195);
end;
/
-- 运行2
exec process_employee(195);

可以看到, 如上代码还是基本上使用了 cs106中的软件设计方法, 即自顶向下, 分而治之的办法.

现在如果用户又打来电话说"还是用姓-空格-名的格式吧", 我们就不用满腹牢骚, 通宵加班的寻找 ||','|| 了. 相反, 我们只需要花上5秒钟来修改 employee_pke.fullname的实现部分, 然后通知用户一切搞定了.

上例代码实现:

 package employee_pkg
as
subtype fullname_t IS varchar2(200); function fullname(
last_in employees.last_name%type,
first_in employees.first_name%type)
return fullname_t; function fullname(
employee_id_in in employees.employee_id%type)
return fullname_t;
end employee_pkg;
/
show errors;
 package body employee_pkg
as
function fullname(
last_in employees.last_name%type,
first_in employees.first_name%type)
return fullname_t
is
begin
return last_in || ' , ' || first_in;
end; function fullname( employee_id_in in employees.employee_id%type)
return fullname_t
is
retval fullname_t;
begin
select fullname(last_name, first_name) into retval
from employees
where employee_id = employee_id_in; return retval;
exception
when no_data_found then
dbms_output.put_line('There is no data');
when too_many_rows then
dbms_output.put_line('There are too many rows');
end;
end employee_pkg;

上边的内容最好分开编译, 先编译声明部分, 再编译包体部分

初始化:oracle 负责保证每个包在每个会话会被初始化一次.

持久化, 除了数据持久化之外, 还有一个会话持久化, 这意味着如果我们连接到oracle数据库(建立了一个会话) 然后执行一个程序给一个包级别的变量(也就是一个在包的规范部分声明的变量, 或者虽然是在包体中声明, 但又游离于包体中的所有程序之外的变量)赋值, 这个变量设置会一直持续会话生命期, 即便执行赋值操作的程序已经结束, 只要会话还没有结束, 这个变量的值就会一直保持.

缓存静态的会话信息

初始化单元可以缓存静态会话信息, 这些信息可以持续整个会话生命期. 不过这样会占用内存, 比如有1000个会话, 那么就要占用1000份内存, 不过这样可以提高CPU提取数据的速度.

包体中, 把缺省值的赋值操作移动到初始化单元中.

例如:

 create or replace package valerr
is
function get return varchar2;
end valerr;
/
show errors;
 create or replace package body valerr
is
-- 一个包级别的, 但是 私有的全局变量
v varchar2(1) := 'ABC'; function get
return varchar2
is
begin
return v;
end; begin -- 注意这个 begin 没有 end; 与之对应
dbms_output.put_line('Before i show you v...');
exception
when others then
dbms_output.put_line('Trapped the error!');
end valerr;

上边的包体中的初始化单元, begin 开始, 但是没有 end; 与之对应, 一定要注意.
为什么要有这个初始化单元的另外一个原因是, 如果你不是在初始化单元定义的变量, 如果发生异常, 是不会被捕获的.

我们可以进一步把包设计的标准化, 以保证总有一个初始化过程, 以提示我们的组员避免以上问题, 例如:

也就是把想要初始化的内容放到一个 procedure 中, 也可以再定义一个验证 初始化 procedure 的 verify_initialization, 然后在初始化单元里包含这两个procedure, 这样更标准化.

包数据可以被那些对这个包邮execute权限的程序使用(包括读取和修改这个值) 共有的包数据非常类似于 oracle forms 中的 global 变量, 也和后者同样危险.

如果在一个包过程中打开了一个游标, 这个游标会在整个会话生命期中一直保持着打开和可用状态.

包游标

在包中声明显示游标

如果我们在声明游标时只是声明了游标头, 我们就必须要在游标定义加上 RETURN 子句, 这个子句用来描述从游标中提取的数据元素.

 create or replace package book_info
is
cursor byauthor_cur( -- 带sql的游标, 整体
author_in in books.author%type)
is
select *
from books
where author = author_in; cursor bytitle_cur( -- 带 return 的游标头
title_filter_in in books.title%type)
return books%rowtype; type author_summary_rt is record(
author books.author%type,
total_page_count pls_integer,
total_book_count pls_integer); cursor summary_cur(
author_id in books.author%type)
return author_summary_rt;
end book_info;
/
show errors;
 create or replace package body book_info
is
cursor bytitle_cur(
title_filter_in in books.title%type)
return books%rowtype
is
select *
from books
where title like upper(title_filter_in); cursor summary_cur(
author_id in books.author%type)
return author_summary_rt
is
select author, sum(page_count), count(*)
from books
where author = author_id;
end book_info;
/
show errors;

注意: 上边包体并没有把包声明中的所有内容都实现, 但是带有 return 的游标必须要实现.

直接定义变量, 是包中一个游标的类型, 然后直接打开, 提取, 关闭 游标就可以了.

以上游标要作为一个整体, 打开, 提取, 关闭 一体就没有问题了.

建议, 专门构建一个打开游标, 关闭游标的过程.

这样, 和包游标有关的所有复杂操作都被放在过程中完成.

刚刚说了, 包是在整个会话期间都可以使用, 占用了大量内存, 但是这样也有好处, 同时也有办法不这样. 这就是包的串行化.

包的串行化

在包声明和包体内都使用 SERIALLY_REUSABLE 这个编译指令, 这种包的包状态(变量值, 包游标的打开状态等)的声明周期可以从整个会话减少到对包的一个程序调用.

例如:

 create or replace package book_info_n
is
pragma serially_reusable; -- 注意这里 procedure fill_list; procedure show_list;
end book_info_n;
/
show errors;
 create or replace package body book_info_n
is
pragma serially_reusable; -- 注意这里 -- ...
end book_info_n;
/
show errors;

关于串行包要注意的内容:

  • 串行包使用的是全局内存是从SGA中分配的, 而不是从用户的UGA中分配的, 这样一来包的工作区就可以重用的, 每次包重用时, 包级别变量都会重新初始化成缺省值或者NULL, 包的初始化单元也会重新执行.
  • 使用串行包所需要的工作区的最大数量取决于冰法使用这个包的用户的数量, SGA内存使用的增加被UGA或者程序内存的减少所抵消. 最后, 如果数据库由于其他的需求需要回收SGA内存, 数据库就会把不再使用的工作期过期处理.

个人感觉一般还是不要使用 串行包.

何时使用包

封装数据操作.

避免直接硬编码: 比如在包中定义一个常量, 在包外可以直接引用.

把逻辑上相关的功能组织在一起

缓存会话的静态数据从而改善应用程序性能( 在一个session 中会始终保存 )

plsql programming 18 包的更多相关文章

  1. plsql programming 13 其他数据类型

    bolean 类型 raw 类型, 用来保存和操作少量的二进制数据. urowid 和 rowid 类型, 这两种数据类型表示数据库的 rowid. 所谓 rowid 就是一个标识符-用来表示数据库中 ...

  2. plsql programming 19 触发器

    挂起语句, 是指数据库 Hang 到那不能动了, 触发的. 1. DML 触发器 这种类型的触发器对于开发人员都很常见, 其他类型的触发器主要是给DBA使用的. 配置触发器,我们需要回答以下问题: 触 ...

  3. plsql programming 17 过程, 函数与参数

    代码模块化, 即将一大块代码拆成若干小块(过程), 然后就可以在其他模块调用这些模块了, 这样, 重用性更好, 也方便管理. 过程: 过程是一个可以像执行 PL/SQL 语句一样调用的程序, 一个过程 ...

  4. 【PLSQL】package包的使用

    ************************************************************************   ****原文:blog.csdn.net/clar ...

  5. plsql programming 20 管理PL/SQL代码(个人感觉用不到)

    这一章的内容, 只完成了一部分, 剩下的用到再补充吧 由于依赖关系, 而编译失败, 需要重新编译. ( 所谓依赖, 是指存储过程, 函数等在运行中调用的对象, 比如table 等, 比如你删除了过程中 ...

  6. plsql programming 14 DML和事务管理

    我们可以把多个SQL语句集中在一起, 在逻辑上组成一个事务, 从而保证这些操作或者全部被保存到数据库(用sql的说法就是”提交”), 或者被整体驳回(用sql的说法是“回滚”). 事务: ACID 原 ...

  7. plsql programming 11 记录类型

    记录类型非常类似数据库表中的行. 记录作为一个整体本身并没有值, 不过每个单独成员或字段都有值, 记录提供了一种把这些值当做一组进行操作的方法. 例如: 1: -- create a table 2: ...

  8. plsql programming 16 动态SQL和动态PLSQL

    动态SQL 是指在执行时才构建 SQL 语句, 相对于静态 sql 的编译时就已经构建. 动态PLSQL 是指整个PL/SQL代码块都是动态构建, 然后再编译执行的. 作用: 1. 可以支持 DDL ...

  9. plsql programming 04 条件和顺序控制

    1. 条件语句 if salary > 40000 or salary is NULL then give_bonus(employee_id, 500); end if; if conditi ...

随机推荐

  1. NF3 里面的z cull reverse reload

    nf3 siggraph2011的 分享 里面有谈对csm的优化. 1.mask white red 2. HI Z 这俩我都懂 3.reverse depth buffer这实在不明白, 为什么会有 ...

  2. Swift-3-字符串和字符

    // Playground - noun: a place where people can play import UIKit var someString = "some string ...

  3. jQuery提升性能技巧及个人总结

    1.将jquery对象缓存起来在for循环中,不要每次都要访问数组的length属性,我们应该先将对象缓存进一个变量然后再操作,如下所示: 代码如下:var myLength = myArray.le ...

  4. HDOJ 1428 漫步校园

    漫步校园 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  5. CSS 的overflow:hidden 属性详细解释

    overflow:hidden这个CSS样式是大家常用到的CSS样式,但是大多数人对这个样式的理解仅仅局限于隐藏溢出, 而对于清除浮动这个含义不是很了解.一提到清除浮动,我们就会想到另外一个CSS样式 ...

  6. Xcode 创建静态库和动态库

    1.linux中静态库和动态库区别: 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种. 静态库:这类库的名字一般是libxxx.a:利用静态函数库编译成的文件 ...

  7. (转)android ListView详解

    转自:  http://www.cnblogs.com/allin/archive/2010/05/11/1732200.html 在android开发中ListView是比较常用的组件,它以列表的形 ...

  8. x86虚拟地址到物理地址的映射学习

    这里只谈分页管理的机制,也是目前最重要的内存管理机制. 最初的设计想法: 结构图如下: 页的尺寸是4KB,虚拟地址的前20位用于指定一个物理页,后12位用于访问页内偏移. 页表项的结构: 各个位的含义 ...

  9. 使用jmeter对websocket进行压力测试[转载]

    前段时间本着练习angularJS+requireJS的目的写了一个基于nodeJS和socket.io的聊天室,github地址为:https://github.com/towersxu/node- ...

  10. C难点分析

    1. 形参和实参 调用函数时,写在括号里面的就是实参,函数本身用的就是形参. 2.字符串问题 char a[5]={"abcd"};注意是4个字符,而不是5个  字符串数组后面带  ...