pl/sql中的exception

  1. 1、异常的优点  
  2.  
  3.   如果没有异常,在程序中,应当检查每个命令的成功还是失败,如  
  4.  
  5.   BEGIN 
  6.  
  7.   SELECT …  
  8.  
  9.   — check for ’no data found’ error  
  10.  
  11.   SELECT …  
  12.  
  13.   — check for ’no data found’ error  
  14.  
  15.   SELECT …  
  16.  
  17.   — check for ’no data found’ error  
  18.  
  19.   这种实现的方法缺点在于错误处理没有与正常处理分开,可读性差,使用异常,可以方便处理错误,而且异常处理程序与正常的事务逻辑分开,提高了可读性,如  
  20.  
  21.   BEGIN 
  22.  
  23.   SELECT …  
  24.  
  25.   SELECT …  
  26.  
  27.   SELECT …  
  28.  
  29.   …  
  30.  
  31.   EXCEPTION  
  32.  
  33.   WHEN NO_DATA_FOUND THEN — catches all ’no data found’ errors  
  34.  
  35.   2、异常的分类  
  36.  
  37.   有两种类型的异常,一种为内部异常,一种为用户自定义异常,内部异常是执行期间返回到PL/SQL块的ORACLE错误或由PL/SQL代码的某操作引起的错误,如除数为零或内存溢出的情况。用户自定义异常由开发者显示定义,在PL/SQL块中传递信息以控制对于应用的错误处理。  
  38.  
  39.   每当PL/SQL违背了ORACLE原则或超越了系统依赖的原则就会隐式的产生内部异常。因为每个ORACLE错误都有一个号码并且在PL/SQL中异常通过名字处理,ORACLE提供了预定义的内部异常。如SELECT INTO 语句不返回行时产生的ORACLE异常NO_DATA_FOUND。对于预定义异常,现将最常用的异常列举如下:  
  40.  
  41.   exception  
  42.  
  43.   oracle error  
  44.  
  45.   sqlcode value  
  46.  
  47.   condition  
  48.  
  49.   no_data_found  
  50.  
  51.   ora-01403  
  52.  
  53.   +100  
  54.  
  55.   select into 语句没有符合条件的记录返回  
  56.  
  57.   too_mang_rows  
  58.  
  59.   ora-01422  
  60.  
  61.   -1422  
  62.  
  63.   select into 语句符合条件的记录有多条返回  
  64.  
  65.   dup_val_on_index  
  66.  
  67.   ora-00001  
  68.  
  69.   -1  
  70.  
  71.   对于数据库表中的某一列,该列已经被限制为唯一索引,程序试图存储两个重复的值  
  72.  
  73.   value_error  
  74.  
  75.   ora-06502  
  76.  
  77.   -6502  
  78.  
  79.   在转换字符类型,截取或长度受限时,会发生该异常,如一个字符分配给一个变量,而该变量声明的长度比该字符短,就会引发该异常  
  80.  
  81.   storage_error  
  82.  
  83.   ora-06500  
  84.  
  85.   -6500  
  86.  
  87.   内存溢出  
  88.  
  89.   zero_divide  
  90.  
  91.   ora-01476  
  92.  
  93.   -1476  
  94.  
  95.   除数为零  
  96.  
  97.   case_not_found  
  98.  
  99.   ora-06592  
  100.  
  101.   -6530  
  102.  
  103.   对于选择case语句,没有与之相匹配的条件,同时,也没有else语句捕获其他的条件  
  104.  
  105.   cursor_already_open  
  106.  
  107.   ora-06511  
  108.  
  109.   -6511  
  110.  
  111.   程序试图打开一个已经打开的游标  
  112.  
  113.   timeout_on_resource  
  114.  
  115.   ora-00051  
  116.  
  117.   -51  
  118.  
  119.   系统在等待某一资源,时间超时  
  120.  
  121.   如果要处理未命名的内部异常,必须使用OTHERS异常处理器或PRAGMA EXCEPTION_INIT 。PRAGMA由编译器控制,或者是对于编译器的注释。PRAGMA在编译时处理,而不是在运行时处理。EXCEPTION_INIT告诉编译器将异常名与ORACLE错误码结合起来,这样可以通过名字引用任意的内部异常,并且可以通过名字为异常编写一适当的异常处理器。  
  122.  
  123.   在子程序中使用EXCEPTION_INIT的语法如下:  
  124.  
  125.   PRAGMA EXCEPTION_INIT(exception_name, -Oracle_error_number);  
  126.  
  127.   在该语法中,异常名是声明的异常,下例是其用法:  
  128.  
  129.   DECLARE 
  130.  
  131.   deadlock_detected EXCEPTION;  
  132.  
  133.   PRAGMA EXCEPTION_INIT(deadlock_detected, -60);  
  134.  
  135.   BEGIN 
  136.  
  137.   … — Some operation that causes an ORA-00060 error  
  138.  
  139.   EXCEPTION  
  140.  
  141.   WHEN deadlock_detected THEN 
  142.  
  143.   — handle the error  
  144.  
  145.   END;  
  146.  
  147.   对于用户自定义异常,只能在PL/SQL块中的声明部分声明异常,异常的名字由EXCEPTION关键字引入:  
  148.  
  149.   reserved_loaned Exception  
  150.  
  151.   产生异常后,控制传给了子程序的异常部分,将异常转向各自异常控制块,必须在代码中使用如下的结构处理错误:  
  152.  
  153.   Exception  
  154.  
  155.   When exception1 then 
  156.  
  157.   Sequence of statements;  
  158.  
  159.   When exception2 then 
  160.  
  161.   Sequence of statements;  
  162.  
  163.   When others then 
  164.  
  165.   3、异常的抛出  
  166.  
  167.   由三种方式抛出异常  
  168.  
  169.   1. 通过PL/SQL运行时引擎  
  170.  
  171.   2. 使用RAISE语句  
  172.  
  173.   3. 调用RAISE_APPLICATION_ERROR存储过程  
  174.  
  175.   当数据库或PL/SQL在运行时发生错误时,一个异常被PL/SQL运行时引擎自动抛出。异常也可以通过RAISE语句抛出  
  176.  
  177.   RAISE exception_name;  
  178.  
  179.   显式抛出异常是程序员处理声明的异常的习惯用法,但RAISE不限于声明了的异常,它可以抛出任何任何异常。例如,你希望用TIMEOUT_ON_RESOURCE错误检测新的运行时异常处理器,你只需简单的在程序中使用下面的语句:  
  180.  
  181.   RAISE TIMEOUT_ON_RESOUCE;  
  182.  
  183.   比如下面一个订单输入的例子,若当订单小于库存数量,则抛出异常,并且捕获该异常,处理异常  
  184.  
  185.   DECLARE 
  186.  
  187.   inventory_too_low EXCEPTION;  
  188.  
  189.   —其他声明语句  
  190.  
  191.   BEGIN 
  192.  
  193.   IF order_rec.qty>inventory_rec.qty THEN 
  194.  
  195.   RAISE inventory_too_low;  
  196.  
  197.   END IF  
  198.  
  199.   EXCEPTION  
  200.  
  201.   WHEN inventory_too_low THEN 
  202.  
  203.   order_rec.staus:=‘backordered’;  
  204.  
  205.   END;  
  206.  
  207.   RAISE_APPLICATION_ERROR内建函数用于抛出一个异常并给异常赋予一个错误号以及错误信息。自定义异常的缺省错误号是+1,缺省信息是User_Defined_Exception。RAISE_APPLICATION_ERROR函数能够在pl/sql程序块的执行部分和异常部分调用,显式抛出带特殊错误号的命名异常。  
  208.  
  209.   Raise_application_error(error_number,message[,true,false]))  
  210.  
  211.   错误号的范围是-20,000到-20,999。错误信息是文本字符串,最多为2048字节。TRUEFALSE表示是添加(TRUE)进错误堆(ERROR STACK)还是覆盖(overwrite)错误堆(FALSE)。缺省情况下是FALSE。  
  212.  
  213.   如下代码所示:  
  214.  
  215.   IF product_not_found THEN 
  216.  
  217.   RAISE_APPLICATION_ERROR(-20123,‘Invald product code’ TRUE);  
  218.  
  219.   END IF;  
  220.  
  221.   4、异常的处理  
  222.  
  223.   PL/SQL程序块的异常部分包含了程序处理错误的代码,当异常被抛出时,一个异常陷阱就自动发生,程序控制离开执行部分转入异常部分,一旦程序进入异常部分就不能再回到同一块的执行部分。下面是异常部分的一般语法:  
  224.  
  225.   EXCEPTION  
  226.  
  227.   WHEN exception_name THEN 
  228.  
  229.   Code for handing exception_name  
  230.  
  231.   [WHEN another_exception THEN 
  232.  
  233.   Code for handing another_exception]  
  234.  
  235.   [WHEN others THEN 
  236.  
  237.   code for handing any other exception.]  
  238.  
  239.   用户必须在独立的WHEN子串中为每个异常设计异常处理代码,WHEN OTHERS子串必须放置在最后面作为缺省处理器处理没有显式处理的异常。当异常发生时,控制转到异常部分,ORACLE查找当前异常相应的WHEN..THEN语句,捕捉异常,THEN之后的代码被执行,如果错误陷阱代码只是退出相应的嵌套块,那么程序将继续执行内部块END后面的语句。如果没有找到相应的异常陷阱,那么将执行WHEN OTHERS。在异常部分WHEN 子串没有数量限制。  
  240.  
  241.   EXCEPTION  
  242.  
  243.   WHEN inventory_too_low THEN 
  244.  
  245.   order_rec.staus:=‘backordered’;  
  246.  
  247.   replenish_inventory(inventory_nbr=>  
  248.  
  249.   inventory_rec.sku,min_amount=>order_rec.qty-inventory_rec.qty);  
  250.  
  251.   WHEN discontinued_item THEN 
  252.  
  253.   –code for discontinued_item processing  
  254.  
  255.   WHEN zero_divide THEN 
  256.  
  257.   –code for zero_divide  
  258.  
  259.   WHEN OTHERS THEN 
  260.  
  261.   –code for any other exception  
  262.  
  263.   END;  
  264.  
  265.   当异常抛出后,控制无条件转到异常部分,这就意味着控制不能回到异常发生的位置,当异常被处理和解决后,控制返回到上一层执行部分的下一条语句。  
  266.  
  267.   BEGIN 
  268.  
  269.   DECLARE 
  270.  
  271.   bad_credit exception;  
  272.  
  273.   BEGIN 
  274.  
  275.   RAISE bad_credit;  
  276.  
  277.   –发生异常,控制转向;  
  278.  
  279.   EXCEPTION  
  280.  
  281.   WHEN bad_credit THEN 
  282.  
  283.   dbms_output.put_line(‘bad_credit’);  
  284.  
  285.   END;  
  286.  
  287.   –bad_credit异常处理后,控制转到这里  
  288.  
  289.   EXCEPTION  
  290.  
  291.   WHEN OTHERS THEN 
  292.  
  293.   –控制不会从bad_credit异常转到这里  
  294.  
  295.   –因为bad_credit已被处理  
  296.  
  297.   END;  
  298.  
  299.   当异常发生时,在块的内部没有该异常处理器时,控制将转到或传播到上一层块的异常处理部分。  
  300.  
  301.   BEGIN 
  302.  
  303.   DECLARE —内部块开始  
  304.  
  305.   bad_credit exception;  
  306.  
  307.   BEGIN 
  308.  
  309.   RAISE bad_credit;  
  310.  
  311.   –发生异常,控制转向;  
  312.  
  313.   EXCEPTION  
  314.  
  315.   WHEN ZERO_DIVIDE THEN –不能处理bad_credite异常  
  316.  
  317.   dbms_output.put_line(‘divide by zero error’);  
  318.  
  319.   END –结束内部块  
  320.  
  321.   –控制不能到达这里,因为异常没有解决;  
  322.  
  323.   –异常部分  
  324.  
  325.   EXCEPTION  
  326.  
  327.   WHEN OTHERS THEN 
  328.  
  329.   –由于bad_credit没有解决,控制将转到这里  
  330.  
  331.   END;  
  332.  
  333.   5、异常的传播  
  334.  
  335.   没有处理的异常将沿检测异常调用程序传播到外面,当异常被处理并解决或到达程序最外层传播停止。在声明部分抛出的异常将控制转到上一层的异常部分。  
  336.  
  337.   BEGIN 
  338.  
  339.   executable statements  
  340.  
  341.   BEGIN 
  342.  
  343.   today DATE:=‘SYADATE’–ERRROR  
  344.  
  345.   BEGIN –内部块开始  
  346.  
  347.   dbms_output.put_line(‘this line will not execute’);  
  348.  
  349.   EXCEPTION  
  350.  
  351.   WHEN OTHERS THEN 
  352.  
  353.   –异常不会在这里处理  
  354.  
  355.   END;–内部块结束  
  356.  
  357.   EXCEPTION  
  358.  
  359.   WHEN OTHERS THEN 
  360.  
  361.   处理异常  
  362.  
  363.   END 

 

本文转自sucre03 51CTO博客,原文链接:http://blog.51cto.com/sucre/371394,如需转载请自行联系原作者

点赞