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

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

 1 create or replace procedure process_employee(
 2     employee_id_in IN employees.employee_id%type)
 3 is
 4     l_full_name varchar2(100);
 5 begin
 6     select last_name || ' , ' || first_name
 7       into l_full_name
 8       from employees
 9      where employee_id = employee_id_in;
10     dbms_output.put_line('The full name is : ' || l_full_name);
11 end;
12 /
13 show errors;
14
15 -- 运行1
16 begin
17     process_employee(195);
18 end;
19 /
20 -- 运行2
21 exec process_employee(195);

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

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

上例代码实现:

 1 package employee_pkg
 2 as
 3     subtype fullname_t IS varchar2(200);
 4
 5     function fullname(
 6         last_in employees.last_name%type,
 7         first_in employees.first_name%type)
 8         return fullname_t;
 9
10     function fullname(
11         employee_id_in in employees.employee_id%type)
12         return fullname_t;
13 end employee_pkg;
14 /
15 show errors;

 1 package body employee_pkg
 2 as
 3     function fullname(
 4         last_in employees.last_name%type,
 5         first_in employees.first_name%type)
 6         return fullname_t
 7     is
 8     begin
 9         return last_in || ' , ' || first_in;
10     end;
11
12     function fullname( employee_id_in in employees.employee_id%type)
13         return fullname_t
14     is
15         retval fullname_t;
16     begin
17         select fullname(last_name, first_name) into retval
18           from employees
19          where employee_id = employee_id_in;
20
21         return retval;
22     exception
23         when no_data_found then
24             dbms_output.put_line('There is no data');
25         when too_many_rows then
26             dbms_output.put_line('There are too many rows');
27     end;
28 end employee_pkg;

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

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

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

缓存静态的会话信息

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

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

例如:

1 create or replace package valerr
2 is
3     function get return varchar2;
4 end valerr;
5 /
6 show errors;

 1 create or replace package body valerr
 2 is
 3     -- 一个包级别的, 但是 私有的全局变量
 4     v varchar2(1) := 'ABC';
 5
 6     function get
 7         return varchar2
 8     is
 9     begin
10         return v;
11     end;
12
13     begin        -- 注意这个 begin 没有 end; 与之对应
14         dbms_output.put_line('Before i show you v...');
15     exception
16         when others then
17             dbms_output.put_line('Trapped the error!');
18 end valerr; 

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

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

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

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

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

包游标

在包中声明显示游标

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

 1 create or replace package book_info
 2 is
 3     cursor byauthor_cur(    -- 带sql的游标, 整体
 4         author_in in books.author%type)
 5     is
 6         select *
 7           from books
 8          where author = author_in;
 9
10     cursor bytitle_cur(        -- 带 return 的游标头
11         title_filter_in in books.title%type)
12         return books%rowtype;
13
14     type author_summary_rt is record(
15         author                 books.author%type,
16         total_page_count    pls_integer,
17         total_book_count    pls_integer);
18
19     cursor summary_cur(
20         author_id in books.author%type)
21         return author_summary_rt;
22 end book_info;
23 /
24 show errors;    

 1 create or replace package body book_info
 2 is
 3     cursor bytitle_cur(
 4         title_filter_in in books.title%type)
 5         return books%rowtype
 6     is
 7         select *
 8           from books
 9          where title like upper(title_filter_in);
10
11     cursor summary_cur(
12         author_id in books.author%type)
13         return author_summary_rt
14     is
15         select author, sum(page_count), count(*)
16           from books
17          where author = author_id;
18 end book_info;
19 /
20 show errors;
21     

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

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

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

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

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

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

包的串行化

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

例如:

 1 create or replace package book_info_n
 2 is
 3     pragma serially_reusable;    -- 注意这里
 4
 5     procedure fill_list;
 6
 7     procedure show_list;
 8 end book_info_n;
 9 /
10 show errors;

1 create or replace package body book_info_n
2 is
3     pragma serially_reusable;    -- 注意这里
4
5     -- ...
6 end book_info_n;
7 /
8 show errors;

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

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

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

何时使用包

封装数据操作.

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

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

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

plsql programming 18 包相关推荐

  1. plsql programming 10 日期和时间戳

    年 月 日 时 分 秒 时区 用小时表示的相对于 UTC 的时差 用分钟表示的相对于 UTC 的时差 date 存储日期和时间, 不带时区, 精确到秒 timestamp 存储日期和时间, 不带时区, ...

  2. PLSQL 触发器,包,定时任务

    --触发器    trigger DML触发器 语法: create or replace trigger 触发器名  before|after       --before指事前触发器,after指 ...

  3. java基础笔记(18)包和导入、权限修饰符、单例模式

    一. 包和导入 关键字:package.import 包的概念: 包的本质就是文件夹,是对项目中的类进行管理的.在代码中,用package明确当前类所在的包. 注:package必须出现在类的第一行 ...

  4. python爬取饿了么奶茶店外卖数据_饿了么爬虫(二)利用Fiddler进行抓包爬虫

    02 - Fiddler抓包 在进行后续步骤前,请在电脑上安装Fiddler. 从我们之前的文章中可以确定饿了么的商品信息是通过json文件进行传输的,Json文件名都是?jsv开始.但是由于这些js ...

  5. 饿了么爬虫(二)利用Fiddler进行抓包爬虫

    之前我们通过保存网页HTML代码的方法对饿了么商品进行爬虫.但是这种方法比较复杂,需要保存非常多的html文件.具体文章可以参阅:http://smilecoc.vip/2020/09/26/%E9% ...

  6. 第三周 Java语法总结__static关键字__代码块__继承__this和super的区别__重写__final关键字__多态__抽象__接口__形参问题__包__权限修饰符__内部类

    文章目录 6.static关键字 1)静态static关键字的特点: 2)关于static关键字的使用注意事项 3)什么时候将变量定义为成员变量: 7.文档说明书: 8.代码块 9.继承 1)继承的概 ...

  7. SVM分类器原理详解

    SVM分类器原理详解 标签: svm文本分类java 2015-08-21 11:51 2399人阅读 评论(0) 收藏 举报  分类: 数据挖掘 文本处理(16)  机器学习 分类算法(10)  目 ...

  8. July大神---SVM讲解

    支持向量机通俗导论(理解SVM的三层境界) 作者:July :致谢:pluskid.白石.JerryLead. 出处:结构之法算法之道blog. 前言 动笔写这个支持向量机(support vecto ...

  9. 五十六、Java的json解析库Json-lib和Gson

    @Author:Runsen @Dater:2020/06/18 文章目录 JSON Json-lib Gson JSON JSON不管是在Web开发还是服务器开发中是相当常见的数据传输格式,一般情况 ...

最新文章

  1. Maven多模块项目中应用maven-tomcat-plugin热部署
  2. 如何在javascript中使用多个分隔符分割字符串?
  3. OWASP依赖性检查Maven插件–必须具备
  4. VC.NET字符指针与String的转换
  5. 关于java 中 的 null。
  6. 1.node.js 概述
  7. journalctl -xe
  8. matlab三相仿真电路实验视频,三相逆变电路MATLAB仿真
  9. 【Arduino实验15 红外遥控电风扇】
  10. Unity Resource文件夹的使用
  11. Mac 升级ruby版本
  12. CAP定理以及BASE定理详解
  13. 京东秒杀技巧有哪些(京东秒杀技巧大全)
  14. PCIE——第5章——Montevina 的 MCH 和 ICH
  15. 专升本高数学习总结——无穷级数
  16. 0基础怎么学习短视频剪辑,并通过剪辑赚钱?
  17. html怎么调整成苹方,web css 苹方字体设置
  18. pydicom提取图片偏绿(光度解释异常)的处理方法
  19. 删除cookie,domain的设置
  20. java数据结构-链表详解

热门文章

  1. 乾坤 微前端_前端优秀资源整理(持续更新~)
  2. 360浏览器极速模式_【小技巧】解除浏览器主页以及,锁定主页~
  3. 3264位Visio 2016怎么下载安装激活方法视频
  4. abap如何找屏幕增强_因增强导致BDC录屏执行异常的梗
  5. java md5包_JAVA中有没有提供MD5算法的包啊?
  6. mySQL双机冗余_MySQL双机热备实现原理
  7. linux专业术语中英文,Linux专业术语中英文对照.doc
  8. golang 中 map 转 struct
  9. mint-ui的Loadmore组件使用示例
  10. 认识HTML5的WebSocket