plsql programming 18 包
所謂包, 就是把一組PL/SQL 的代碼元素組織在一個(gè)命名空間下.
另外, 包的用法就類似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 -- 運(yùn)行1 16 begin 17 process_employee(195); 18 end; 19 / 20 -- 運(yùn)行2 21 exec process_employee(195);可以看到, 如上代碼還是基本上使用了 cs106中的軟件設(shè)計(jì)方法, 即自頂向下, 分而治之的辦法.
現(xiàn)在如果用戶又打來電話說"還是用姓-空格-名的格式吧", 我們就不用滿腹牢騷, 通宵加班的尋找 ||','|| 了. 相反, 我們只需要花上5秒鐘來修改 employee_pke.fullname的實(shí)現(xiàn)部分, 然后通知用戶一切搞定了.
上例代碼實(shí)現(xiàn):
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;上邊的內(nèi)容最好分開編譯, 先編譯聲明部分, 再編譯包體部分
初始化:oracle 負(fù)責(zé)保證每個(gè)包在每個(gè)會(huì)話會(huì)被初始化一次.
持久化, 除了數(shù)據(jù)持久化之外, 還有一個(gè)會(huì)話持久化, 這意味著如果我們連接到oracle數(shù)據(jù)庫(建立了一個(gè)會(huì)話) 然后執(zhí)行一個(gè)程序給一個(gè)包級(jí)別的變量(也就是一個(gè)在包的規(guī)范部分聲明的變量, 或者雖然是在包體中聲明, 但又游離于包體中的所有程序之外的變量)賦值, 這個(gè)變量設(shè)置會(huì)一直持續(xù)會(huì)話生命期, 即便執(zhí)行賦值操作的程序已經(jīng)結(jié)束, 只要會(huì)話還沒有結(jié)束, 這個(gè)變量的值就會(huì)一直保持.
緩存靜態(tài)的會(huì)話信息
初始化單元可以緩存靜態(tài)會(huì)話信息, 這些信息可以持續(xù)整個(gè)會(huì)話生命期. 不過這樣會(huì)占用內(nèi)存, 比如有1000個(gè)會(huì)話, 那么就要占用1000份內(nèi)存, 不過這樣可以提高CPU提取數(shù)據(jù)的速度.
包體中, 把缺省值的賦值操作移動(dòng)到初始化單元中.
例如:
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 -- 一個(gè)包級(jí)別的, 但是 私有的全局變量 4 v varchar2(1) := 'ABC'; 5 6 function get 7 return varchar2 8 is 9 begin 10 return v; 11 end; 12 13 begin -- 注意這個(gè) begin 沒有 end; 與之對(duì)應(yīng) 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; 與之對(duì)應(yīng), 一定要注意.
為什么要有這個(gè)初始化單元的另外一個(gè)原因是, 如果你不是在初始化單元定義的變量, 如果發(fā)生異常, 是不會(huì)被捕獲的.
我們可以進(jìn)一步把包設(shè)計(jì)的標(biāo)準(zhǔn)化, 以保證總有一個(gè)初始化過程, 以提示我們的組員避免以上問題, 例如:
也就是把想要初始化的內(nèi)容放到一個(gè) procedure 中, 也可以再定義一個(gè)驗(yàn)證 初始化 procedure 的 verify_initialization, 然后在初始化單元里包含這兩個(gè)procedure, 這樣更標(biāo)準(zhǔn)化.
包數(shù)據(jù)可以被那些對(duì)這個(gè)包郵execute權(quán)限的程序使用(包括讀取和修改這個(gè)值) 共有的包數(shù)據(jù)非常類似于 oracle forms 中的 global 變量, 也和后者同樣危險(xiǎn).
如果在一個(gè)包過程中打開了一個(gè)游標(biāo), 這個(gè)游標(biāo)會(huì)在整個(gè)會(huì)話生命期中一直保持著打開和可用狀態(tài).
包游標(biāo)
在包中聲明顯示游標(biāo)
如果我們?cè)诼暶饔螛?biāo)時(shí)只是聲明了游標(biāo)頭, 我們就必須要在游標(biāo)定義加上 RETURN 子句, 這個(gè)子句用來描述從游標(biāo)中提取的數(shù)據(jù)元素.
1 create or replace package book_info 2 is 3 cursor byauthor_cur( -- 帶sql的游標(biāo), 整體 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 的游標(biāo)頭 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注意: 上邊包體并沒有把包聲明中的所有內(nèi)容都實(shí)現(xiàn), 但是帶有 return 的游標(biāo)必須要實(shí)現(xiàn).
直接定義變量, 是包中一個(gè)游標(biāo)的類型, 然后直接打開, 提取, 關(guān)閉 游標(biāo)就可以了.
以上游標(biāo)要作為一個(gè)整體, 打開, 提取, 關(guān)閉 一體就沒有問題了.
建議, 專門構(gòu)建一個(gè)打開游標(biāo), 關(guān)閉游標(biāo)的過程.
?
這樣, 和包游標(biāo)有關(guān)的所有復(fù)雜操作都被放在過程中完成.
剛剛說了, 包是在整個(gè)會(huì)話期間都可以使用, 占用了大量內(nèi)存, 但是這樣也有好處, 同時(shí)也有辦法不這樣. 這就是包的串行化.
包的串行化
在包聲明和包體內(nèi)都使用 SERIALLY_REUSABLE 這個(gè)編譯指令, 這種包的包狀態(tài)(變量值, 包游標(biāo)的打開狀態(tài)等)的聲明周期可以從整個(gè)會(huì)話減少到對(duì)包的一個(gè)程序調(diào)用.
例如:
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;關(guān)于串行包要注意的內(nèi)容:
- 串行包使用的是全局內(nèi)存是從SGA中分配的, 而不是從用戶的UGA中分配的, 這樣一來包的工作區(qū)就可以重用的, 每次包重用時(shí), 包級(jí)別變量都會(huì)重新初始化成缺省值或者NULL, 包的初始化單元也會(huì)重新執(zhí)行.
- 使用串行包所需要的工作區(qū)的最大數(shù)量取決于冰法使用這個(gè)包的用戶的數(shù)量, SGA內(nèi)存使用的增加被UGA或者程序內(nèi)存的減少所抵消. 最后, 如果數(shù)據(jù)庫由于其他的需求需要回收SGA內(nèi)存, 數(shù)據(jù)庫就會(huì)把不再使用的工作期過期處理.
個(gè)人感覺一般還是不要使用 串行包.
何時(shí)使用包
封裝數(shù)據(jù)操作.
避免直接硬編碼: 比如在包中定義一個(gè)常量, 在包外可以直接引用.
把邏輯上相關(guān)的功能組織在一起
緩存會(huì)話的靜態(tài)數(shù)據(jù)從而改善應(yīng)用程序性能( 在一個(gè)session 中會(huì)始終保存 )
?
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的plsql programming 18 包的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux从零到高手的进阶心得
- 下一篇: Win7如何快速打开命令提示符