暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PLSQL的异常处理

全栈精英 2021-08-24
1377

(本文使用Oracle19c 和 scott表)

异常处理

异常处理是防范程序的执行错误或未预料到的事件

ORACLE异常以 ORA-xxxxx 形式呈现 (其中xxxxx为错误编号),使用 EXCEPTION 和异常处理 EXCEPTION HANDLER 来实现错误处理

注意异常处理不是解决编译错误的,因为编译错误发生在程序执行前

如果产生异常而没有处理时,程序就会自动终止整个程序运行

异常处理的格式

 EXCEPTION
    WHEN 异常名称1 THEN <处理异常1的代码>
    WHEN 异常名称2 THEN <处理异常2的代码>
    WHEN OTHERS THEN <处理其它异常的代码>
 END;
复制

异常的分类:

  • 预定义异常

  • 非预定义异常

  • 用户自定义异常

预定义异常

ORACLE预定义的异常情况大约有24个。对这种异常情况的处理,无需在程序中定义,由ORACLE自动将其引发

处理方式是在PL/SQL块的异常处理部分,直接引用相应的异常情况名,并对其完成相应的异常错误处理即可

预定义异常表

 错误号    异常错误信息名称    说明  
 ORA-0001    Dup_val_on_index    违反了唯一性限制  
 ORA-0051    Timeout-on-resource    在等待资源时发生超时  
 ORA-0061    Transaction-backed-out    由于发生死锁事务被撤消  
 ORA-1001    Invalid-CURSOR    试图使用一个无效的游标  
 ORA-1012    Not-logged-on    没有连接到ORACLE  
 ORA-1017    Login-denied    无效的用户名/口令  
 ORA-1403    No_data_found    SELECT INTO没有找到数据  
 ORA-1422    Too_many_rows    SELECT INTO 返回多行  
 ORA-1476    Zero-divide    试图被零除  
 ORA-1722    Invalid-NUMBER    转换一个数字失败  
 ORA-6500    Storage-error    内存不够引发的内部错误  
 ORA-6501    Program-error    内部错误  
 ORA-6502    Value-error    转换或截断错误  
 ORA-6504    Rowtype-mismatch    宿主游标变量与 PL/SQL变量有不兼容行类型  
 ORA-6511    CURSOR-already-OPEN    试图打开一个已处于打开状态的游标  
 ORA-6530    Access-INTO-null    试图为null  对象的属性赋值  
 ORA-6531    Collection-is-null    试图将Exists  以外的集合( collection)方法应用于一个null  pl/sql 表上或varray上  
 ORA-6532    Subscript-outside-limit    对嵌套或varray索引得引用超出声明范围以外  
 ORA-6533    Subscript-beyond-count    对嵌套或varray 索引得引用大于集合中元素的个数.  

例:更新指定员工工资,如工资小于1500,则加100(使用异常处理) 

    DECLARE
    -- 声明变量保存员工号和工资
    v_empno emp.empno%TYPE := &员工号;
    v_sal emp.sal%TYPE;
    BEGIN
    -- 先查询工资
    SELECT sal INTO v_sal FROM emp WHERE empno = v_empno;
    -- if语句判断工资是否1500以内
    IF v_sal<=1500 THEN
    -- 如果是:修改工资+100
    UPDATE emp SET sal = sal + 100 WHERE empno=v_empno;
    DBMS_OUTPUT.PUT_LINE(v_empno||'员工工资已更新!');
    COMMIT;
    ELSE
    -- 如果不是:只输出提示不做修改
    DBMS_OUTPUT.PUT_LINE(v_empno||'员工工资已经超过1500!');
    END IF;

    -- 注意: 异常的写法
    EXCEPTION
    -- 先处理:预定义的NO_DATA_FOUND异常
    WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('数据库中没有编码为'||v_empno||'的员工');
    -- 再处理:预定义的TOO_MANY_ROWS异常
    WHEN TOO_MANY_ROWS THEN
    DBMS_OUTPUT.PUT_LINE('程序运行错误!请使用游标');
    -- 最后处理:其它可能会有的异常
    WHEN OTHERS THEN
    -- SQLCODE:错误码,SQLERRM:错误消息
    DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
    END;
    复制
    区别 NO_DATA_FOUND 和 %NOTFOUND:
    复制
    • SELECT … INTO 语句触发 NO_DATA_FOUND

    • 当一个显式游标的WHERE子句未找到时触发%NOTFOUND

    • 当UPDATE或DELETE 语句的WHERE 子句未找到时触发 SQL%NOTFOUND

    • 在提取循环中要用 %NOTFOUND 或%FOUND 来确定循环的退出条件,不要用 NO_DATA_FOUND

    非预定义异常

    即其它标准的 ORACLE 异常。对这种异常情况的处理,需要用户在程序中定义,然后由ORACLE自动将其引发

    步骤:

    • 定义异常

    • 使用EXCEPTION_INIT将定义的异常与标准的ORACLE错误关联

    • 执行异常处理

    例:删除指定部门的记录信息,以确保该部门没有员工 (使用异常处理) 

      DECLARE
      v_deptno dept.deptno%TYPE := &部门号;
      deptno_remaining EXCEPTION;
      -- -2292 是违反一致性约束的错误代码
      PRAGMA EXCEPTION_INIT(deptno_remaining, -2292);
      BEGIN
      -- 删除部门
      DELETE FROM dept WHERE deptno = v_deptno;
      COMMIT;
      -- 异常处理
      EXCEPTION
      -- 处理非预定义异常的异常
      WHEN deptno_remaining THEN
      DBMS_OUTPUT.PUT_LINE('违反数据完整性约束!');
      -- 处理其它可能会有的异常
      WHEN OTHERS THEN
      DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
      END;
      复制
      用户自定义异常
      复制

      程序执行过程中,出现开发人员认为的非正常情况。对这种异常情况的处理,需要用户在程序中定义,然后在程序中将其引发

      做法是:通过使用 RAISE 语句来抛出异常,程序控制就转向到 EXCEPTION块异常错误部分,执行错误处理代码

      步骤:

      • 定义异常

      • 使用RAISE抛出异常

      • 执行异常处理

      例:更新指定员工工资,如果更新失败,抛出异常 

        DECLARE
        -- 声明员工号变量
        v_empno emp.empno%TYPE :=&员工号;
        -- 声明自定义的异常
        no_result EXCEPTION;
        BEGIN
        -- 修改该员工的工资
        UPDATE emp SET sal = sal+100 WHERE empno = v_empno;
        -- 如果员工号不存在,修改操作失败
        IF SQL%NOTFOUND THEN
        -- 抛出自定义异常
        RAISE no_result;
        END IF;
        -- 异常处理
        EXCEPTION
        -- 处理抛出的自定义异常
        WHEN no_result THEN
        DBMS_OUTPUT.PUT_LINE('你的数据更新语句失败了!');
        -- 处理其它的异常
        WHEN OTHERS THEN
        DBMS_OUTPUT.PUT_LINE(SQLCODE||'---'||SQLERRM);
        END;
        复制
        复制

        附:用户自定义异常还可以用 RAISE_APPLICATION_ERROR 的语法 重新定义异常错误消息

         RAISE_APPLICATION_ERROR(错误码,错误消息,[keep_errors] );
        复制

        说明:

        • 错误码 是从 –20,000 到 –20,999 之间的参数

        • 错误消息 是相应的提示信息(< 2048 字节),

        • keep_errors 为可选,如果keep_errors =TRUE , 则新错误将被添加到已经引发的错误列表中。如果keep_errors=FALSE(缺省),则新错误将替换当前的错误列表

        文章转载自全栈精英,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论