林秀麗 鄒貴紅 盧道設(shè)
摘要:編程領(lǐng)域無論是高手還是新手,程序編寫過程中或業(yè)務(wù)邏輯處理中,遇到難以周全考慮的錯(cuò)誤是很正常的,所以任何一個(gè)優(yōu)秀程序都應(yīng)該帶有對(duì)異常的捕獲、提示、處理并恢復(fù)的功能。目的提高程序的健壯性。該文以O(shè)RACLE數(shù)據(jù)庫(kù)為例,對(duì)異常處理進(jìn)行剖析。
關(guān)鍵詞:ORACLE數(shù)據(jù)庫(kù);程序健壯性;異常處理
中圖分類號(hào):TP311 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2018)10-0003-03
Abstract: Either the master or novice programming, During the preparation process or business logic processing, It is difficult to take into account the error is normal, So any good programs should be with and on the recovery of abnormal, suggesting that capture, processing function,Objective to improve the robustness of the program。In this paper, the ORACLE database as an example, Analysis of exception handling.
Key words: ORACLE database; the robustness of the program; exception handling
程序編寫中,錯(cuò)誤總會(huì)遇到不少,錯(cuò)誤一般分為兩種,一種是輸入錯(cuò)誤,另一種是邏輯性錯(cuò)誤[1]。ORACLE將錯(cuò)誤進(jìn)行了歸納,即:編譯時(shí)刻錯(cuò)誤;運(yùn)行時(shí)刻錯(cuò)誤(也稱異常錯(cuò)誤)。
1 異常處理分類
1.1 編譯時(shí)刻錯(cuò)誤
編譯錯(cuò)誤是因用戶錯(cuò)誤的拼寫關(guān)鍵字、對(duì)象名以及錯(cuò)誤的語法格式等造成,此類錯(cuò)誤在編譯時(shí)PL/SQL引擎會(huì)發(fā)并報(bào)告給用戶,此時(shí)程序是處在運(yùn)行前。
例1:查詢中數(shù)據(jù)表名輸入錯(cuò),編譯時(shí),PL/SQL引擎立馬發(fā)現(xiàn)錯(cuò)誤并提示。
1.2 運(yùn)行時(shí)刻錯(cuò)誤(異常錯(cuò)誤)
編譯即便通過,錯(cuò)誤在運(yùn)行時(shí)刻還是有可能產(chǎn)生。運(yùn)行時(shí)刻錯(cuò)誤產(chǎn)生的原因有很多,例如:硬件故障、內(nèi)存不足、表的完整性約束被違反、被零除、數(shù)據(jù)在大小長(zhǎng)度上的不匹配等[2][3]。
編譯時(shí)刻錯(cuò)誤在程序內(nèi)部沒必要做特殊處理。對(duì)運(yùn)行時(shí)刻錯(cuò)誤,因運(yùn)行環(huán)境的不確定性此錯(cuò)誤可能會(huì)隨時(shí)出現(xiàn)。程序員必須在寫程序過程中,對(duì)潛在的異常錯(cuò)誤要盡可能的考慮并做針對(duì)性的處理,目的提高程序的健壯性。
PL/SQL對(duì)運(yùn)行時(shí)刻錯(cuò)誤提供了自動(dòng)捕獲與處理機(jī)制。
例2:被零除錯(cuò)誤產(chǎn)生的異常,在PL/SQL引擎編譯可以通過,只在運(yùn)行時(shí)刻錯(cuò)誤才呈現(xiàn)。
2 異常錯(cuò)誤處理
對(duì)程序中出現(xiàn)的異常錯(cuò)誤要進(jìn)行處理,異常處理結(jié)構(gòu)是固定的,如下:
異常定義區(qū)對(duì)預(yù)定義異常是不需要進(jìn)行定義的;異常執(zhí)行是可以顯式引發(fā)異常,也可以由PL/SQL引擎引發(fā)異常;若引發(fā)了異常,則引發(fā)異常的后續(xù)語句將停止執(zhí)行,語句轉(zhuǎn)向異常處理區(qū),直到異常處理完成,再回來。
異常分為預(yù)定義異常(系統(tǒng)預(yù)定義異常,非預(yù)定義異常)以及用戶定義異常。這兩種異常有不同的定義和引發(fā)方式,但對(duì)處理異常錯(cuò)誤的程序編寫方法與執(zhí)行過程是一樣的。
無論是哪一類異常,ORACLE在引發(fā)異常時(shí)都有一個(gè)序號(hào),但程序進(jìn)行異常處理時(shí),不直接使用異常序號(hào),異常的引用與處理必須使用名字。
2.1 預(yù)定義異常
預(yù)定義異常分為兩類:第一類是系統(tǒng)預(yù)定義異常,此類異常是系統(tǒng)定義的,提供了異常序號(hào)與異常名稱,二十來個(gè),可直接使用,但在異常的捕獲與處理上太有限。第二類是非預(yù)定異常,此類異常系統(tǒng)只提供了異常產(chǎn)生時(shí)的序號(hào),并沒有提供異常名,在程序中要捕獲這類異常,用戶就必須自己聲明異常的名稱,用EXCEPTION_INT編譯命令建立異常序號(hào)同異常名稱的聯(lián)系,當(dāng)程序發(fā)生異常時(shí),就會(huì)自動(dòng)以該名稱引發(fā)對(duì)應(yīng)序號(hào)的異常錯(cuò)誤。
例3:系統(tǒng)預(yù)定義異常??捎枚鄺l件選擇,在CASE語句的WHEN條件部分,引發(fā)系統(tǒng)預(yù)定義的CASE_NOT_FOUNT異常錯(cuò)誤,異常處理部分可直接使用異常錯(cuò)誤名稱對(duì)異常錯(cuò)誤進(jìn)行捕獲。
例4:非預(yù)定義異常。在插入語句中出現(xiàn)插入異常錯(cuò)誤,系統(tǒng)提供了異常錯(cuò)誤序號(hào)(ORA-01400),但系統(tǒng)并沒有給此序號(hào)以對(duì)應(yīng)的名稱,用戶就必須自己聲明名稱(ept_null_error),然后同異常錯(cuò)誤序號(hào)ORA-01400對(duì)應(yīng),這樣程序就可以按異常名稱ept_null_error捕獲處理異常。
預(yù)定義異常還可以通過SQLCODE和SQLERRM內(nèi)置函數(shù)來處理,但此兩函數(shù)在SQL語句中均不能直接使用,需要先將它們賦值給變量后,才能在SQL語句中使用。
SQLCODE函數(shù)不帶參數(shù),返回的是ORACLE錯(cuò)誤序號(hào)。SQLERRM函數(shù)參數(shù)可寫可不寫,若寫參數(shù)則為錯(cuò)誤序號(hào),此函數(shù)帶參數(shù)時(shí)返回其錯(cuò)誤序號(hào)對(duì)應(yīng)的錯(cuò)誤消息文本,若省去參數(shù)此函數(shù)返回SQLCODE當(dāng)前值對(duì)應(yīng)的錯(cuò)誤消息文本。
例5:SQLCODE返回的錯(cuò)誤序號(hào)為-2292,SQLERRM返回的是錯(cuò)誤序號(hào)-2292的錯(cuò)誤消息文本“ORA-02292: 違反完整約束條件 (HR.COUNTR_REG_FK) - 已找到子記錄”。
2.2 自定義異常
ORACLE能判斷的異常錯(cuò)誤且能提供異常錯(cuò)誤序號(hào)的只有預(yù)定義異常,但在實(shí)際使用中遠(yuǎn)遠(yuǎn)不能滿足異常處理的要求。程序員必須自定義一些異常,來滿足具體業(yè)務(wù)規(guī)則以及程序的編程與調(diào)試需求。自定義異常往往不一定是什么錯(cuò)誤,而是讓程序的結(jié)構(gòu)完美。如:利用異常處理部分對(duì)某些問題進(jìn)行集中處理。
必須先聲明自定義異常,且異常引發(fā)要用RAISE語句顯示拋出,自定義異常沒有異常序號(hào)。
對(duì)于自定義異常也可以使用RAISE_APPLICATION_ERROR過程來實(shí)現(xiàn),此函數(shù)對(duì)異常的錯(cuò)誤序號(hào)與異常的錯(cuò)誤消息文本都可自定義,使用靈活方便。此過程很多時(shí)候是為應(yīng)用程序編程風(fēng)格提供方便,不一定非要用于異常錯(cuò)誤的處理。
例6:建一個(gè)使用了RAISE_APPLICATION_ERROR的過程dept_mgr,此過程是判斷一個(gè)部門是否有管理員的情況自定義異常錯(cuò)誤代碼“-20001”,“-20002”與對(duì)應(yīng)消息文本“該部門編碼超出了取值范圍”,“該部門沒有管理員”。僅接著調(diào)用dept_mgr過程,按部門編碼與該部門有沒有管理員來捕獲異常錯(cuò)誤。
3 異常傳遞
當(dāng)異常被引發(fā)時(shí),就會(huì)立馬跳轉(zhuǎn)到EXCEPTION的異常處理語句中查詢是否有匹配的異常,若在當(dāng)前語句塊或者子語句塊中都沒有匹配的異常,那么此異常就會(huì)向當(dāng)前語句塊的外層或子語句塊的調(diào)用方傳遞,直到搜索塊終止還沒有匹配的異常,此時(shí)就會(huì)向PL/SQL引擎拋出一個(gè)未處理的異常。
以下詳細(xì)剖析異常的傳遞機(jī)制[4][5]。
3.1 異常傳遞引發(fā)于執(zhí)行部分
在當(dāng)前塊的執(zhí)行部分引發(fā)異常的處理機(jī)制:若在當(dāng)前塊中有匹配的異常處理,則執(zhí)行該異常處理,然后將控制權(quán)傳到外層語句塊;若在當(dāng)前塊中沒有匹配的異常處理,則異常會(huì)被傳到外層的異常處理部分查詢匹配的異常處理;若異常一直被傳遞直到最外層語句塊,都沒查詢到匹配的異常處理,則該程序?qū)惓=Y(jié)束,且在被調(diào)用環(huán)境中顯示錯(cuò)誤信息。
如圖2,異常1在當(dāng)前塊中有匹配的異常處理;異常2被傳遞到外層塊中有匹配的異常處理對(duì)應(yīng);異常3是沒有查詢到匹配的異常處理的。
3.2 異常傳遞引發(fā)于聲明部分
異常傳遞引發(fā)于聲明部分,如變量在初始化是產(chǎn)生異常錯(cuò)誤,此時(shí)異常會(huì)立馬向外層塊傳遞,而不被當(dāng)前塊的異常處理部分捕獲。
如圖3,A 變量定義長(zhǎng)度為3,可賦值長(zhǎng)度超過了3,結(jié)果引發(fā)異常錯(cuò)誤,此異常錯(cuò)誤是向外層塊傳遞的。
3.3 異常傳遞引發(fā)于異常內(nèi)部
異常傳遞引發(fā)于異常內(nèi)部,是指異常在處理中也有引發(fā)異常的可能。異常內(nèi)部引發(fā)異常,是會(huì)立馬被傳遞到外層語句塊,不論本塊是否能進(jìn)行異常處理。異常內(nèi)部引發(fā)異常,可有RAISE顯式引發(fā),或者因某種錯(cuò)誤由ORACLE檢測(cè)到進(jìn)行隱式引發(fā)。
如圖4,異常2引發(fā)于異常1內(nèi)部,結(jié)果被傳遞到外層塊處理。
4 結(jié)論
本文對(duì)PL/SQL中的異常進(jìn)行了剖析,從程序的健壯性闡述了異常的分類,對(duì)異常的處理機(jī)制分為兩種,一種是預(yù)定義異常,一種是自定義異常,當(dāng)預(yù)定義異常不能滿足程序需要時(shí),自定義異??梢耘缮嫌脠?chǎng)。同時(shí)詳細(xì)介紹了異常的不同傳遞。以便初學(xué)者深入理解異常處理機(jī)制,開發(fā)人員靈活使用異常機(jī)制解決問題。
參考文獻(xiàn):
[1] 李興華,馬云濤. Oracle開發(fā)經(jīng)典[M].北京:清華大學(xué)出版社,2012(16):436-448.
[2] 龔永罡. Oracle 11g管理與應(yīng)用實(shí)踐教程[M].北京:清華大學(xué)出版社,2014(7).
[3] 路川,胡欣杰. Oracle 11g寶典[M].北京:電子工業(yè)出版社,2009(4):198-207.
[4] 谷長(zhǎng)勇,吳逸云,單永紅,陳杰. Oracle 11g權(quán)威指南[M]. 2版.北京:電子工業(yè)出版社,2011(18).
[5] 明昌科技. Oracle從入門到精通[M].北京:清華大學(xué)出版社,2012(14).