--pl/sql程序执行过程中出现的错误,称之为异常。根据其严重程序,需要做不同的处理。
一、异常的基本概念
没有错误处理的pl/sql应用程序不是一个完善的应用程序,这样的程序代码在执行过程中,
经常会出现程序不能正常执行,执行中的程序突然终止执行,甚至造成系统崩溃。为了能够设计
出对可能出现的各种错误进行相应处理的程序,pl/sql语言提供了异常处理机制。
1.异常处理机制
pl/sql程序的错误分为两类:一类是pl/sql的语法错误,它由pl/sql编译器发现并给出错误信息。
另一类是运行时错误,编译器发现的错误,由于不能修改程序就无法执行,因此编译错误由
程序员来修改。
oracle中对运行时错误的处理采用了异常处理机制。一个错误对应一个异常,当错误产生时就抛出
相应的异常,并被异常处理器(异常处理代码)捕获,程序控制权传递给异常处理器,由异常处理器
来处理运行时的错误。
2.异常分类
pl/sql语言的异常分为两大类,一类是oracle系统异常,另一类是自定义异常。
oracle系统异常又分为两种,一种是预定义异常,另一种是非预定义异常。
(1)预定义异常
预定义异常是Oracle系统异常中的一种,用于处理常见的Oracle错误。
Oracle预定义异常的特点是,Oracle系统定义了它们的错误编号与异常名字。
当运行pl/sql代码产生预定义错误时,与错误对应的预定义异常被自动抛出,通过预定义
异常名字捕获该异常,并对错误进行处理。
(2)非预定义异常
非预定义异常也是Oracle系统异常中的一种,用于处理预定义以外的Oracle系统错误。
它的特点是,Oracle系统定义了它们的错误编号,但没有定义异常名字。这些oracle系统错误没有
预定义异常(异常名字)与其关联,需要在pl/sql块的声明部分定义一个异常名字,然后通过伪过程
pragma exception_init将该异常名字与一个oracle错误编号相关联。这样,当运行pl/sql代码产生非预定义
错误时,与错误代码对应的非预定义异常被自动抛出,通过定义的异常名字捕获该异常,并对错误进行处理。
(3)自定义异常
自定义异常用于处理用户定义错误,即处理与Oracle系统错误无关的其他错误,自定义异常是指有些操作
并不会产生Oracle系统错误,但是程序员从业务规则角度考虑,认为是一个错误。例如,执行update操作
没有更新任何记录行时,不会引发Oracle系统错误,也不会产生异常。但是,有时需要开发人员为此操作
产生一个异常,以便进行处理,这就是用户定义异常。
3.异常处理过程
如果捕获到异常,可以在pl/sql块内处理异常,也可以不在pl/sql块内处理异常。如果不在pl/sql块内处理异常,
那么,Oracle会把异常传递到调用它的pl/sql块或pl/sql程序运行环境。
在pl/sql程序中,异常处理的三个步骤:
定义异常。在声明部分为错误定义异常。
抛出异常。pl/sql语句执行过程中产生错误时,招聘与错误对应的异常。
捕获及处理异常。
(1)定义异常
定义异常的方法是在pl/sql程序的声明部分定义一个exception类型的变量。
语法格式:
exception_name exception;
如果是非预定义异常同学需要使用伪过程,在编译阶段将异常名与一个Oracle错误代码相关联,
语法格式:
pragma exception_init(exception_name, error_number);
--exception_name为异常名,error_number为Oracle系统内部错误号,用一个负位数表示,
-20999至-20000为用户定义错误的保留号。
(2)抛出异常。
由于系统不能自动识别用户定义错误,因此当产生自定义错误时,需要程序员使用特定的pl/sql
代码抛出相应的自定义异常。
语法格式:
raise exception_name;
(3)捕获及处理异常
异常捕获语句对各类异常加以识别,对不同异常分别进行各自的处理。
语法格式:
1 exception 2 when e_name1[or e_name2...] then 3 sequence of statements1; 4 when e_name3[or e_name4...] then 5 sequence of statements2; 6 ... 7 [when others 8 sequence of_statementsn;] 9 end;
二、系统异常处理
1.预定义异常
1 declare 2 v_dividend number := 50; 3 v_divisor number := 0; 4 v_quotient number; 5 begin 6 v_quotient := v_dividend/v_divisor; 7 exception 8 when zero_divide then 9 dbms_output.put_line('除数为零!'); 10 end; 11 set serveroutput on 12 declare 13 v_specialty students.specialty%type; 14 v_name students.name%type; 15 begin 16 v_specialty := '&specialty'; 17 select name into v_sname 18 from students where specialty = v_specialty; 19 dbms_output.put_line('学生姓名:'|| v_sname); 20 exception 21 when too_many_rows then 22 dbms_output.put_line('返回的学生记录多于一行!'); 23 when no_data_found then 24 dbms_output.put_line('输入的专业不存在!'); 25 end;
2.非预定义异常
非预定义异常需要用户定义异常名,而且还需要使用伪过程,在编译阶段将异常名与
一个Oracle错误代码相关联。
1 set serveroutput on 2 declare 3 e_deptid exception; 4 pragma exception_init(e_deptid, -2292); 5 begin 6 delete from departments 7 where department_id = 101; 8 exception 9 when e_deptid then 10 dbms_output.put_line('在老师表中存在子记录!'); 11 end;
3.自定义异常处理
自定义异常处理不仅需要用户定义异常名字,而且需要程序员安排何时抛出异常。
1 set serveroutput on 2 declare 3 e_wage exception; 4 v_wage teachers.wage%type; 5 begin 6 v_wage := &wage; 7 insert into teachers 8 values(10111, '王彤', '教授', '01-9月-1990', 1000, v_wage, 101); 9 if v_wage < 0 then 10 raise e_wage; 11 end if; 12 exception 13 when e_wage then 14 dbms_output.put_line('教师工资不能为负值!'); 15 end; 16 set serveroutput on 17 declare 18 e_wage exception; 19 v_wage teachers.wage%type; 20 v_deptid teachers.department_id%type; 21 v_bonus teachers.bonus%type; 22 begin 23 v_wage := &wage; 24 v_deptid := &department_id; 25 insert into teachers 26 values(10111, '王彤', '教授', '01-9月-1990', 1000, v_wage, 101); 27 select bonus into v_bonus 28 from teachers 29 where department_id = v_deptid; 30 if v_wage < 0 then 31 raise e_wage; 32 end if; 33 exception 34 when e_wage then 35 dbms_output.put_line('教师工资不能为负值!'); 36 rollback; 37 when others then 38 dbms_output.put_line('查询老师资金时出错!'); 39 end;
4.使用异常函数
在pl/sql代码运行出现错误时,通过使用异常函数可以获得错误代码以及相关的错误描述。
其中函数sqlcode用于获得Oracle错误代码,而sqlerrm则用于获得与之相应的错误描述。
1 set serveroutput on 2 declare 3 e_wage exception; 4 v_wage teachers.wage%type; 5 v_deptid teachers.department_id%type; 6 v_bonus teachers.bonus%type; 7 begin 8 v_wage := &wage; 9 v_deptid := &department_id; 10 insert into teachers 11 values(10111, '王彤', '教授', '01-9月-1990', 1000, v_wage, 101); 12 select bonus into v_bonus 13 from teachers 14 where department_id = v_deptid; 15 if v_wage < 0 then 16 raise e_wage; 17 end if; 18 exception 19 when e_wage then 20 dbms_output.put_line('教师工资不能为负值!'); 21 rollback; 22 when others then 23 dbms_output.put_line('错误代码:'||sqlcode); 24 dbms_output.put_line('错误描述:'||sqlerrm); 25 end;