熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Oracle >> 正文

全面解析Oracledeveloper的異常處理機制

2013-11-13 15:42:46  來源: Oracle 

  Oracle developer以其快速的數據處理開發而聞名其異常處理機制也是比較完善不可小觑

   異常的優點

  如果沒有異常在程序中應當檢查每個命令的成功還是失敗

  

  BEGIN

  SELECT

   check for no data found error

  SELECT

   check for no data found error

  SELECT

   check for no data found error

  這種實現的方法缺點在於錯誤處理沒有與正常處理分開可讀性差使用異常可以方便處理錯誤而且異常處理程序與正常的事務邏輯分開提高了可讀性

  

  BEGIN

  SELECT

  SELECT

  SELECT

  

  EXCEPTION

  WHEN NO_DATA_FOUND THEN catches all no data found errors

   異常的分類

  有兩種類型的異常一種為內部異常一種為用戶自定義異常內部異常是執行期間返回到PL/SQL塊的ORACLE錯誤或由PL/SQL代碼的某操作引起的錯誤如除數為零或內存溢出的情況用戶自定義異常由開發者顯示定義在PL/SQL塊中傳遞信息以控制對於應用的錯誤處理

  每當PL/SQL違背了ORACLE原則或超越了系統依賴的原則就會隱式的產生內部異常因為每個ORACLE錯誤都有一個號碼並且在PL/SQL中異常通過名字處理ORACLE提供了預定義的內部異常如SELECT INTO 語句不返回行時產生的ORACLE異常NO_DATA_FOUND對於預定義異常現將最常用的異常列舉如下

  exception oracle error sqlcode value condition

  no_data_found ora + select into 語句沒有符合條件的記錄返回

  too_mang_rows ora select into 語句符合條件的記錄有多條返回

  dup_val_on_index ora 對於數據庫表中的某一列該列已經被限制為唯一索引程序試圖存儲兩個重復的值

  value_error ora 在轉換字符類型截取或長度受限時會發生該異常如一個字符分配給一個變量而該變量聲明的長度比該字符短就會引發該異常

  storage_error ora 內存溢出

  zero_divide ora 除數為零

  case_not_found ora 對於選擇case語句沒有與之相匹配的條件同時也沒有else語句捕獲其他的條件

  cursor_already_open ora 程序試圖打開一個已經打開的游標

  timeout_on_resource ora 系統在等待某一資源時間超時

  如果要處理未命名的內部異常必須使用OTHERS異常處理器或PRAGMA EXCEPTION_INIT PRAGMA由編譯器控制或者是對於編譯器的注釋PRAGMA在編譯時處理而不是在運行時處理EXCEPTION_INIT告訴編譯器將異常名與ORACLE錯誤碼結合起來這樣可以通過名字引用任意的內部異常並且可以通過名字為異常編寫一適當的異常處理器

  在子程序中使用EXCEPTION_INIT的語法如下

   PRAGMA EXCEPTION_INIT(exception_name Oracle_error_number);

  在該語法中異常名是聲明的異常下例是其用法

  

  DECLARE

  deadlock_detected EXCEPTION;

  PRAGMA EXCEPTION_INIT(deadlock_detected );

  BEGIN

   Some operation that causes an ORA error

  EXCEPTION

  WHEN deadlock_detected THEN

   handle the error

  END;

  對於用戶自定義異常只能在PL/SQL塊中的聲明部分聲明異常異常的名字由EXCEPTION關鍵字引入

   reserved_loaned Exception

  產生異常後控制傳給了子程序的異常部分將異常轉向各自異常控制塊必須在代碼中使用如下的結構處理錯誤

  

  Exception

  When exception then

  Sequence of statements;

  When exception then

  Sequence of statements;

  When others then

  異常的拋出

  由三種方式拋出異常

  ◆ 通過PL/SQL運行時引擎

  ◆ 使用RAISE語句

  ◆ 調用RAISE_APPLICATION_ERROR存儲過程

  當數據庫或PL/SQL在運行時發生錯誤時一個異常被PL/SQL運行時引擎自動拋出異常也可以通過RAISE語句拋出

  RAISE exception_name

  顯式拋出異常是程序員處理聲明的異常的習慣用法但RAISE不限於聲明了的異常它可以拋出任何任何異常例如你希望用TIMEOUT_ON_RESOURCE錯誤檢測新的運行時異常處理器你只需簡單的在程序中使用下面的語句

  RAISE TIMEOUT_ON_RESOUCE

  比如下面一個訂單輸入的例子若當訂單小於庫存數量則拋出異常並且捕獲該異常處理異常

  

  DECLARE

  inventory_too_low EXCEPTION;

  其他聲明語句

  BEGIN

  IF order_recqty>inventory_recqty THEN

  RAISE inventory_too_low;

  END IF

  EXCEPTION

  WHEN inventory_too_low THEN

  order_recstaus:=backordered;

  END;

  RAISE_APPLICATION_ERROR內建函數用於拋出一個異常並給異常賦予一個錯誤號以及錯誤信息自定義異常的缺省錯誤號是+缺省信息是User_Defined_ExceptionRAISE_APPLICATION_ERROR函數能夠在pl/sql程序塊的執行部分和異常部分調用顯式拋出帶特殊錯誤號的命名異常 Raise_application_error(error_numbermessage[truefalse]))

  錯誤號的范圍是錯誤信息是文本字符串最多為字節TRUE和FALSE表示是添加(TRUE)進錯誤堆(ERROR STACK)還是覆蓋(overwrite)錯誤堆(FALSE)缺省情況下是FALSE

  如下代碼所示

  

  IF product_not_found THEN

  RAISE_APPLICATION_ERROR(Invald product code TRUE);

  END IF;

  異常的處理

  PL/SQL程序塊的異常部分包含了程序處理錯誤的代碼當異常被拋出時一個異常陷阱就自動發生程序控制離開執行部分轉入異常部分一旦程序進入異常部分就不能再回到同一塊的執行部分下面是異常部分的一般語法

  

  EXCEPTION

  WHEN exception_name THEN

  Code for handing exception_name

  [WHEN another_exception THEN

  Code for handing another_exception]

  [WHEN others THEN

  code for handing any other exception]

  用戶必須在獨立的WHEN子串中為每個異常設計異常處理代碼WHEN OTHERS子串必須放置在最後面作為缺省處理器處理沒有顯式處理的異常當異常發生時控制轉到異常部分ORACLE查找當前異常相應的WHEN……THEN語句捕捉異常THEN之後的代碼被執行如果錯誤陷阱代碼只是退出相應的嵌套塊那麼程序將繼續執行內部塊END後面的語句如果沒有找到相應的異常陷阱那麼將執行WHEN OTHERS在異常部分WHEN 子串沒有數量限制

  

  EXCEPTION

  WHEN inventory_too_low THEN

  order_recstaus:=backordered;

  replenish_inventory(inventory_nbr=>

  inventory_recskumin_amount=>order_recqtyinventory_recqty);

  WHEN discontinued_item THEN

  code for discontinued_item processing

  WHEN zero_divide THEN

  code for zero_divide

  WHEN OTHERS THEN

  code for any other exception

  END;

  當異常拋出後控制無條件轉到異常部分這就意味著控制不能回到異常發生的位置當異常被處理和解決後控制返回到上一層執行部分的下一條語句

  

  BEGIN

  DECLARE

  bad_credit exception;

  BEGIN

  RAISE bad_credit;

  發生異常控制轉向

  EXCEPTION

  WHEN bad_credit THEN

  dbms_outputput_line(bad_credit);

  END;

  bad_credit異常處理後控制轉到這裡

  EXCEPTION

  WHEN OTHERS THEN

  控制不會從bad_credit異常轉到這裡

  因為bad_credit已被處理

  END;

  當異常發生時在塊的內部沒有該異常處理器時控制將轉到或傳播到上一層塊的異常處理部分

  BEGIN

  DECLARE 內部塊開始

  bad_credit exception;

  BEGIN

  RAISE bad_credit;

  發生異常控制轉向

  EXCEPTION

  WHEN ZERO_DIVIDE THEN 不能處理bad_credite異常

  dbms_outputput_line(divide by zero error);

  END 結束內部塊

  控制不能到達這裡因為異常沒有解決

  異常部分

  EXCEPTION

  WHEN OTHERS THEN

  由於bad_credit沒有解決控制將轉到這裡

  END;

  異常的傳播

  沒有處理的異常將沿檢測異常調用程序傳播到外面當異常被處理並解決或到達程序最外層傳播停止在聲明部分拋出的異常將控制轉到上一層的異常部分

  

  BEGIN

  executable statements

  BEGIN

  today DATE:=SYADATE; ERRROR

  BEGIN 內部塊開始

  dbms_outputput_line(this line will not execute);

  EXCEPTION

  WHEN OTHERS THEN

  異常不會在這裡處理

  END;內部塊結束

  EXCEPTION

  WHEN OTHERS THEN

  處理異常

  END

  執行部分拋出的異常將首先傳遞到同一塊的異常部分如果在同一塊的異常部分沒有處理這個異常的處理器那麼異常將會傳播到上一層的異常部分中一直到最外層

  在異常部分拋出的異常將控制轉到上一層的異常部分

  另外錯誤報告函數SQLCODE和SQLERRM在OTHERS處理器中特別有用因為它們返回ORACLE錯誤代碼和消息如下例所示

  

  declare

  err_num NUMBER;

  err_msg VARCHAR();

  BEGIN

  

  EXCEPTION

  WHEN OTHERS THEN

  err_num := SQLCODE;

  err_msg := SUBSTR(SQLERRM );

  INSERT INTO errors VALUES (err_num err_msg);

  END;

  有關於異常處理的個知識點

  EXCEPTION_INT編譯指示

  功能是將某命名異常同某特定Oracle錯誤關聯起來

  主用用來捕捉某特定異常錯誤而不是通過OTHERS來處理

  語法PROGMA EXCEPTION_INIT(exception_nameoracle_error_number)

  

  SQL>

  SQL> DECLARE

   expa EXCEPTION;

   PRAGMA EXCEPTION_INIT(expa);

   vn NUMBER();

   BEGIN

   vn:=;

   EXCEPTION

   WHEN expa THEN

   dbms_outputput_line(數字或值錯誤 : 數值精度太高);

   WHEN OTHERS THEN

   dbms_outputput_line(SQLCODE);

   dbms_outputput_line(substr(SQLERRM));

   END;

   /

  數字或值錯誤 : 數值精度太高

  

  PL/SQL procedure successfully completed

  

  SQL>

  RAISE_APPLICATION_ERROR

  功能用來自定義錯誤消息

  語法 RAISE_APPLICATION_ERROR(error_numbererror_message[keep_errors])

  error_number 之間的值

  error_message必須少於個字符

  keep_errors布爾值為真則新的錯誤將被加到已存在的錯誤清單中(如果已存在的話)為假(默認值)則新的錯誤將代替當前的錯誤清單

  

  SQL> BEGIN

   UPDATE t SET a=TEST WHERE a=;

   IF SQL%NOTFOUND THEN

   raise_application_error(你傻了?知道沒有這樣的數據還去更新!);

   END IF;

   EXCEPTION

   WHEN OTHERS THEN

   dbms_outputput_line(substr(SQLERRM));

   END;

   /

  ORA: 你傻了?知道沒有這樣的數據還去更新!

  

  PL/SQL procedure successfully completed

  

  SQL>

  異常傳播

  A可執行部分發生的異常

  )如果當前語句塊有該異常的處理程序則執行之控制權交由外層語句塊

  當前語句塊有該異常的處理程序

  

  SQL> DECLARE

   expa EXCEPTION;

   expb EXCEPTION;

   BEGIN

   BEGIN

   RAISE expa;

   EXCEPTION

   WHEN expa THEN

   dbms_outputput_line(異常A產生);

   END;

   EXCEPTION

   WHEN expb THEN

   dbms_outputput_line(異常B產生);

   END;

   /

  異常A產生

  

  PL/SQL procedure successfully completed

  

  SQL>

  )如果當前語句沒有該異常的處理程序則通過外層語句塊中產生該異常來傳播該異常然後通過外層異常處理程序按步驟1來處理若外層沒有該異常的處理程序則異常傳播到調用環境

  當前語句塊沒有該異常的處理程序外層語句塊中產生該異常並處理

  

  SQL> DECLARE

   expa EXCEPTION;

   expb EXCEPTION;

   BEGIN

   BEGIN

   RAISE expb;

   EXCEPTION

   WHEN expa THEN

   dbms_outputput_line(異常A產生);

   END;

   EXCEPTION

   WHEN expb THEN

   dbms_outputput_line(異常B產生);

   END;

   /

  異常B產生

  

  PL/SQL procedure successfully completed

  

  SQL>

  當前語句塊沒有該異常的處理程序外層語句塊中產生該異常且沒有該異常處理程序異常傳播到調用環境

  

  SQL> DECLARE

   expa EXCEPTION;

   expb EXCEPTION;

   BEGIN

   BEGIN

   RAISE expb;

   EXCEPTION

   WHEN expa THEN

   dbms_outputput_line(異常A產生);

   END;

   EXCEPTION

   WHEN expa THEN

   dbms_outputput_line(異常A產生);

   END;

   /

  

  DECLARE

  expa EXCEPTION;

  expb EXCEPTION;

  BEGIN

  BEGIN

  RAISE expb;

  EXCEPTION

  WHEN expa THEN

  dbms_outputput_line(異常A產生);

  END;

  EXCEPTION

  WHEN expa THEN

  dbms_outputput_line(異常A產生);

  END;

  

  ORA: PL/SQL: 無法處理的用戶自定義異常事件

  ORA: 在line

  

  SQL>

  B聲明部分發生的異常

  聲明部分某賦值發生異常該異常被立即傳播到外層語句塊之後按"A可執行部分發生的異常"規則來處理

  

  SQL> BEGIN

   DECLARE

   vn NUMBER():=;

   BEGIN

   NULL;

   EXCEPTION

   WHEN OTHERS THEN

   dbms_outputput_line(異常在內層被處理!);

   END;

   EXCEPTION

   WHEN OTHERS THEN

   dbms_outputput_line(異常在外層被處理!);

   END;

   /

  異常在外層被處理!

  

  PL/SQL procedure successfully completed

  

  SQL>

  C異常部分發生的異常

  異常處理器中也會產生異常如RAISE或運行錯誤產生這裡異常立即被傳播到外層同"B聲明部分發生的異常"

  例子

  

  SQL>

  SQL> BEGIN

   DECLARE

   expa EXCEPTION;

   expb EXCEPTION;

   BEGIN

   RAISE expa;

   EXCEPTION

   WHEN expa THEN

   RAISE expb;

   WHEN expb THEN

   這裡雖然有expb異常處理語句但是該異常會立即傳播到外層

   dbms_outputput_line(內層捕捉到異常B);

   END;

   EXCEPTION

   WHEN OTHERS THEN

   dbms_outputput_line(外層捕捉到異常B);

   END;

   /

  外層捕捉到異常B

  

  PL/SQL procedure successfully completed

  

  SQL>

  例子

  

  SQL> desc t;

  Name Type

  

  ID NUMBER()

  

  SQL> BEGIN

   DECLARE

   expa EXCEPTION;

   BEGIN

   RAISE expa;

   EXCEPTION

   WHEN expa THEN

   INSERT INTO t VALUES();

   WHEN OTHERS THEN

   dbms_outputput_line(內層捕捉到異常);

   END;

   EXCEPTION

   WHEN OTHERS THEN

   dbms_outputput_line(外層捕捉到異常);

   END;

   /

  外層捕捉到異常

  

  PL/SQL procedure successfully completed

  SQL>

  

   ::在plsql中oracle自帶的Exceptions如下

  Exception Oracle Error SQLCODE Value

  ACCESS_INTO_NULL ORA

  CASE_NOT_FOUND ORA

  COLLECTION_IS_NULL ORA

  CURSOR_ALREADY_OPEN ORA

  DUP_VAL_ON_INDEX ORA

  INVALID_CURSOR ORA

  INVALID_NUMBER ORA

  LOGIN_DENIED ORA

  NO_DATA_FOUND ORA +

  NOT_LOGGED_ON ORA

  PROGRAM_ERROR ORA

  ROWTYPE_MISMATCH ORA

  SELF_IS_NULL ORA

  STORAGE_ERROR ORA

  SUBSCRIPT_BEYOND_COUNT ORA

  SUBSCRIPT_OUTSIDE_LIMIT ORA

  SYS_INVALID_ROWID ORA

  TIMEOUT_ON_RESOURCE ORA

  TOO_MANY_ROWS ORA

  VALUE_ERROR ORA

  ZERO_DIVIDE ORA

  Oracle內置函數SQLCODE和SQLERRM是特別用在OTHERS處理器中分別用來返回Oracle的錯誤代碼和錯誤消息

  OTHERS處理器應該是異常處理塊中的最後的異常處理器因為它是用來捕獲除了別的異常處理器處理以外的所有的Oracle異常所以在程序的最外層使用一個OTHERS處理器的話將可以確保所有的錯誤都會被檢測到

  在一個內在的異常中SQLCODE返回Oracle錯誤的序號而SQLERRM返回的是相應的錯誤消息錯誤消息首先顯示的是錯誤代碼SQLCODE返回的是負數除非Oracle的錯誤為ORANO DATA FOUND(譯ORA未找到數據)當Oracle錯誤為ORANO DATA FOUND其對應的SQLCODE為+對於用戶自定義的異常SQLCODE返回的是+而SQLERRM返回的是UserDefined Exception

  一個Oracle的錯誤消息最多只能包含個字節的錯誤代碼如果沒有異常被觸發則SQLCODE返回SQLERRM返回ORAnormal successful completion


From:http://tw.wingwit.com/Article/program/Oracle/201311/17175.html
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.