将PL/SQL代码封装在灵巧的包中(二)

2015-07-21 16:26:22 · 作者: · 浏览: 1
义包timer_pkg!!!

Code Listing 6: The timer_pkg package

CREATE OR REPLACE PACKAGE timer_pkg IS PROCEDURE start_timer; PROCEDURE show_elapsed (message_in IN VARCHAR2 := NULL); END timer_pkg; / CREATE OR REPLACE PACKAGE BODY timer_pkg IS g_start_time NUMBER := NULL; PROCEDURE start_timer IS BEGIN g_start_time := DBMS_UTILITY.get_cpu_time; END; PROCEDURE show_elapsed (message_in IN VARCHAR2 := NULL) IS BEGIN DBMS_OUTPUT.put_line ( message_in || ': ' || TO_CHAR (DBMS_UTILITY.get_cpu_time - g_start_time)); start_timer; END; END timer_pkg; / 

改写之前的匿名块,如下:

BEGIN timer_pkg.start_timer; FOR indx IN 1 .. 10000 LOOP NULL; END LOOP; timer_pkg.show_elapsed ('10000 Nothings'); END; /

哇哦!good job!

不再需要声明本地变量,不再需要理解GET_CPU_TIME function 如何工作!

3 子程序重载
我们都知道DBMS_OUTPUT.PUT_LINE用于往控制台打印字符数据,

BEGIN DBMS_OUTPUT.PUT_LINE (100); END;

其有一个弊端,只能输出字符类型!

SQL> BEGIN 2 DBMS_OUTPUT.PUT_LINE (TRUE); 3 END; 4 / DBMS_OUTPUT.PUT_LINE (TRUE); * ERROR at line 2: ORA-06550: line 2, column 4: PLS-00306: wrong number or types of arguments in call to ‘PUT_LINE’

多尴尬! 比较BOOLEAN类型无法转成字符类型!

很多开发者不得不这么搞:

IF l_student_is_registered THEN DBMS_OUTPUT.PUT_LINE ('TRUE'); ELSE DBMS_OUTPUT.PUT_LINE ('FALSE'); END IF;

不得不说精神可嘉!
但是,我们有更好的方式:
Code Listing 7: The my_output package without overloading

CREATE OR REPLACE PACKAGE my_output IS PROCEDURE put_line (value_in IN VARCHAR2); PROCEDURE put_line (value_in IN BOOLEAN); PROCEDURE put_line ( value_in IN DATE, mask_in IN VARCHAR2 DEFAULT 'YYYY-MM-DD HH24:MI:SS'); END my_output; /

这就充分发挥了重载的价值!

4 包状态及ORA-04068错误
这个问题是任何开发包的人都无法回避的。
包有状态?
当一个包有至少一个常量或变量声明在包级别,该包就有了状态!
当一个会话调用有状态包,PGA将包所有包级别数据存储起来!

如果一个状态包重新编译,所有使用该包的会话在下次调用时都会抛出:ORA-04068错误。
因为存储在PGA中包级别数据已经过期了(out of date)!所以包必须再次初始化!

此外,一旦ORA-04068抛出,会话中所有状态包,例如,DBMS_OUTPUT都将标识为未初始化。这通常意味着用户
必须断开会话重新连接。

这个潜在的错误意味着当IT部门需要升级应用,他们需要确保所有用户已注销。 但是在7*24的互联网世界这是
不能容忍的。

所以在Oracle 11g r2中,oracle提供了基于版本的重定义功能(Edition-Based Redefinition feature)。