1.情景展示
在Oracle當中,當遇到負責的業務邏輯時,我們可能會需要寫多個存儲過程;
如果這些存錯過程又有依賴關系,比如說:B存儲過程只能等到A存儲過程執行完畢才能執行,如何實現?
2.具體分析
在Oracle當中,也有包package的概念,我們可以將多個存儲過程交由包來統一管理。
包結構如下:
常用的就是:Functions、Procedures、Types、Variables、Constants和Exceptions。
說明:
PACKAGE由PACKAGE和PACKAGE BODY構成;
具體的代碼實現,需要寫在PACKAGE BODY當中(比如:存儲過程)。
PACKAGE BODY當中的內容可以相互訪問,比如:在B存儲過程當中可以調用A存儲過程。
如果需要外界調用的話,必須在PACKAGE當中聲明,外部才能訪問得到。
3.解決方案
打開plsql,在對象窗口當中,找到Packages;
右鍵--》新建;
給包起個名字,最好以PKG_開頭,方便我們識別。
生成的默認格式如下:
tyepe、constant、variable和function,我們都用不到,直接刪掉;
點擊左上角的運行按鈕;
PKG_TEST將會創建成功,並且會自動為PKG_TEST創建PACKAGE BODY;
此時,報錯信息不用擔心,將多余的代碼全部刪除;
再次點擊左上角的執行按鈕,PKG_TEST的body就會創建成功。
這個里面可以寫多個存儲過程。
需要注意的是:
腳本需要寫在PACKAGE BODY里面,並且查看或者編輯的時候,我們也只能通過PACKAGE BODY。
如果這些存儲過程需要外部能夠調用得到的話,需要我們在PACKAGE當中引入它們。
也就是說,要想通過外界訪問得到的內容,需要在放在PACKAGE當中進行聲明。
5.如何調用?
以存儲過程為例;
既可以查看/編輯PACKAGE,也可以查看/編輯PACKAGE BODY。
點擊要執行的存儲過程,右鍵,測試;
打開測試窗口,進行存儲過程調用測試即可。
具體用法見文末推薦。
4.擴展延伸
通常情況下,當我們在PACKAGE BODY當中,創建多個存儲過程后,我們往往還會額外創建一個存儲過程;
這個存儲過程里面調用其它需要執行的存儲過程;
查看代碼
create or replace package body PKG_TEST is
procedure PRO_TEST1(IN_FRCODE VARCHAR2) is
begin
delete FROM BASE_ORG_INFO WHERE AREA = IN_FRCODE;
commit;
end;
procedure PRO_TEST2(IN_FRCODE VARCHAR2) is
begin
delete FROM BASE_ORG_INFO WHERE AREA = IN_FRCODE;
commit;
end;
procedure PRO_TEST3(IN_FRCODE VARCHAR2) is
begin
delete FROM BASE_ORG_INFO WHERE AREA = IN_FRCODE;
commit;
end;
/*統一管理要調用的存儲過程,並決定存儲過程的執行順序。*/
procedure PRO_MAIN(IN_FRCODE VARCHAR2) is
begin
--調用內部存儲過程
PRO_TEST1(IN_FRCODE);
PRO_TEST2(IN_FRCODE);
PRO_TEST3(IN_FRCODE);
end;
end PKG_TEST;
然后,僅僅將該存儲過程通過PACKAGE暴露出去,供外部調用。
查看代碼
create or replace package PKG_TEST is
-- Author : MARYDON
-- Created : 2022/3/11 9:52:57
-- Purpose : 測試包
-- 聲明在這里的存儲過程外界可以通過包名進行調用
/*將主存儲過程暴露出去,供外部調用*/
procedure PRO_MAIN(IN_FRCODE VARCHAR2);
end PKG_TEST;
這樣一來,不僅提高了安全性、可維護性和可擴展性,調用方也不需要關注里面的內部實現,對雙方而言都有好處,這其實是java當中的封裝特性。
2022年3月14日18:41:37
我們知道,現在可以調用PKG_TEST.PROMAIN(),傳入參數完成調用;
如果我們需要調用多次話,可以使用定時器創建定時執行任務。
定時任務可以解決同一個參數值多次調用的問題
但是,無法解決傳多個不同值調用的問題,除了創建不同定時器這種笨方法外,我們還可以:
多個不同值之間使用逗號隔開,然后在調用的main()當中,循環調用。
/*統一管理要調用的存儲過程*/
procedure PRO_MAIN(IN_FRCODE VARCHAR2) is
v_level number;
begin
--統計逗號個數
select lengthb(translate(in_frcode, ',' || in_frcode, ','))
into v_level
from dual;
--將in_frcode按逗號拆分,放到游標當中,循環調用
for cur_frcode in (select regexp_substr(in_frcode,
'[^,]+',
1,
level,
'i') frcode
from dual
connect by level <= v_level + 1) loop
--調用內部存儲過程
PRO_TEST1(cur_frcode.frcode);
PRO_TEST2(cur_frcode.frcode);
PRO_TEST3(cur_frcode.frcode);
end loop;
end;
定期器當中指定入參時,按照逗號將多個frcode隔開即可。
5.異常
2022年3月14日17:19:38
如果,在保存包體PACKAGE BODY時,出現形如:xxx is declared in a package specification and must be defined in the package body的錯誤。
這是因為PACKAGE 當中對於該存儲過程的聲明與在PACKAGE BODY當中的定義,不完全一致導致的。