目录
- 阅读准备事项
- 异常简介
- 捕捉并处理异常
- 预定义异常
- 非预定义异常
- 自定义异常
- 使用异常处理函数
- 使用编译警告
阅读准备事项
添加外键关联:
ALTER TABLE dept_learn ADD CONSTRAINT pk_dept_deptid PRIMARY KEY (department_id); ALTER TABLE emp_learn ADD CONSTRAINT fk_emp_dept_deptid FOREIGN KEY (department_id) REFERENCES dept_learn(department_id);
异常简介
在PL/SQL块中捕获并处理异常,可以提高程序的健壮性,使得应用程序可以安全正常的运行。异常是一种PL/SQL标识符,它有预定义异常、非预定义异常和自定义异常三种类型。在PL/SQL块中,如果不捕获和处理异常,oracle会将错误传递到调用环境。
本节学习目标:
- 学会使用上面介绍的3种异常。
- 学会使用异常处理函数。
- 学会使用PL/SQL编译警告。
异常使用语法:
DECLARE statements;
BEGIN
statements;
EXCEPTION
WHEN exception1 [OR exception2 ...] THEN
statements;
[WHEN exception3 [OR exception4 ...] THEN
statements;]
[WHEN OTHERS THEN
statements;]
END;
捕捉并处理异常
- 预定义异常
指由PL/SQL所提供的系统异常。oracle为开发人员提供了21个预定义异常(将在本节末尾一一列出),每个预定义异常对应一个特定的oracle错误,当PL/SQL块出现这些oracle错误时,会隐含的触发相应的预定义异常。
示例:
1 DECLARE 2 v_name emp_learn.first_name%TYPE; 3 BEGIN 4 SELECT first_name INTO v_name FROM emp_learn WHERE department_id = &dno; 5 dbms_output.put_line('雇员号'||&dno||'的名字为:'||v_name); 6 EXCEPTION 7 WHEN NO_DATA_FOUND THEN 8 dbms_output.put_line('不存在该部门!'); 9 WHEN TOO_MANY_ROWS THEN 10 dbms_output.put_line('该部门有多个员工!'); 11 WHEN OTHERS THEN 12 dbms_output.put_line('未知错误!'); 13 END;
- 非预定义异常
非预定义异常用于处理与预定义异常无关的oracle错误。预定义异常只能处理21种oracle错误,而PL/SQL块可能还会遭遇其它oracle错误,此时可能需要用到非预定义异常了。 非预定义异常使用步骤:
a)定义异常标识符。必须在定义部分定义异常标识符。
b)在oracle错误号和异常之间建立关联。需要在定义部分引用伪过程EXCEPTION_INIT。
c)捕捉并处理异常。
示例:在此节的开始时,我们为emp_learn和dept_learn变建立了外键关联,当更新雇员的部门号时,部门号必须在dept_learn表中存在,否则会触发ORA-02291错误。
SQL> UPDATE emp_learn SET department_id=2000 WHERE employee_id = 198; ORA-02291: 违反完整约束条件 (HR.FK_EMP_DEPT_DEPTID) - 未找到父项关键字
1 DECLARE 2 e_int EXCEPTION; 3 PRAGMA EXCEPTION_INIT(e_int,-2291); 4 v_name emp_learn.first_name%TYPE:=LOWER('&name'); 5 v_deptno dept_learn.department_id%TYPE:=&dno; 6 BEGIN 7 UPDATE emp_learn SET department_id=v_deptno WHERE LOWER(first_name) = v_name; 8 EXCEPTION 9 WHEN e_int THEN 10 dbms_output.put_line('该部门不存在!'); 11 END;
- 自定义异常
在上面“使用非预定义异常处理ora-02291错误”的示例代码中,如果输入一个不存在的雇员的first_name,将不会更新到行数据,不会触发e_int这个非预定义异常,PL/SQL将不会给出任何提示信息。如果此时需要获取到某些信息,或者做某些操作的话,就需要用到自定义异常了,使用步骤:
a)定义异常标识符。必须在定义部分定义。
b)主动触发异常。使用RAISE语句显式触发。
c)捕获并处理异常。
示例:
1 DECLARE 2 e_int EXCEPTION; 3 e_int_norows EXCEPTION; 4 PRAGMA EXCEPTION_INIT(e_int,-2291); 5 v_name emp_learn.first_name%TYPE:=LOWER('&name'); 6 v_deptno dept_learn.department_id%TYPE:=&dno; 7 BEGIN 8 UPDATE emp_learn SET department_id=v_deptno WHERE LOWER(first_name) = v_name; 9 IF SQL%NOTFOUND THEN 10 RAISE e_int_norows; 11 END IF; 12 EXCEPTION 13 WHEN e_int THEN 14 dbms_output.put_line('该部门不存在!'); 15 WHEN e_int_norows THEN 16 dbms_output.put_line('该雇员不存在!'); 17 END;
使用异常处理函数
异常处理函数用于取得oracle错误号和错误消息,其中函数SQLCODE用于取得错误号,SQLERRM用于取得错误消息。当编写PL/SQL块时,通过在异常处理部分引用函数SQLCODE和SQLERRM,可以取得未预计到的oracle错误。通过使用内置过程RAISE_APPLICATION_ERROR,可以在建立子程序(过程、函数和包)时自定义错误号和错误消息。
RAISE_APPLICATION_ERROR过程只适用于数据库子程序(过程、函数、包、触发器),语法:
raise_application_error(error_number,message,[,{TRUE | FALSE}]);
当第三个参数设置为TRUE,则错误会存放到先前错误堆栈,否则会替换先前所有错误。
示例:
1 DECLARE 2 e_int EXCEPTION; 3 PRAGMA EXCEPTION_INIT(e_int,-20000); 4 BEGIN 5 DELETE FROM dept_learn WHERE department_id=&dno; 6 IF SQL%NOTFOUND THEN 7 raise_application_error(-20000,'该部门不存在!'); 8 END IF; 9 EXCEPTION 10 WHEN e_int THEN 11 dbms_output.put_line('错误号:'||SQLCODE||',错误消息:'||SQLERRM); 12 WHEN OTHERS THEN 13 dbms_output.put_line('others-错误号:'||SQLCODE||',错误消息:'||SQLERRM); 14 END;
使用编译警告
使用比较少,以后在加上去。