在本章中,我们将讨论和学习pl/sql中的异常。 程序执行过程中的错误情况是一个例外(异常)。 pl/sql支持程序员在程序中使用exception
块捕获这些发生错误的条件,并针对错误情况采取适当的措施。pl/sql中有两种异常 -
异常处理的一般语法如下。在这里,可以列举尽可能多的异常并且指定处理方式。默认的异常将使用when...then
处理,如下语法所示 -
declare
<declarations section>
begin
<executable command(s)>
exception
<exception handling goes here >
when exception1 then
exception1-handling-statements
when exception2 then
exception2-handling-statements
when exception3 then
exception3-handling-statements
........
when others then
exception3-handling-statements
end;
下面写一个代码来说明和理解这个概念,这里使用前面章节中创建和使用的customers
表,结构和数据如下 -
create table customers(
id int not null,
name varchar (20) not null,
age int not null,
address char (25),
salary decimal (18, 2),
primary key (id)
);
-- 向customers表中插入一些数据记录
insert into customers (id,name,age,address,salary)
values (1, 'ramesh', 32, 'ahmedabad', 2000.00 );
insert into customers (id,name,age,address,salary)
values (2, 'khilan', 25, 'delhi', 1500.00 );
insert into customers (id,name,age,address,salary)
values (3, 'kaushik', 23, 'kota', 2000.00 );
insert into customers (id,name,age,address,salary)
values (4, 'chaitali', 25, 'mumbai', 6500.00 );
insert into customers (id,name,age,address,salary)
values (5, 'hardik', 27, 'bhopal', 8500.00 );
insert into customers (id,name,age,address,salary)
values (6, 'komal', 22, 'mp', 4500.00 );
下面是一个未找到数据记录时的异常处理 -
set serveroutput on size 99999;
declare
c_id customers.id%type := 100;
c_name customers.name%type;
c_addr customers.address%type;
begin
select name, address into c_name, c_addr
from customers
where id = c_id;
dbms_output.put_line ('姓名: '|| c_name);
dbms_output.put_line ('地址: ' || c_addr);
exception
when no_data_found then
dbms_output.put_line('没有找到符合条件的客户信息!');
when others then
dbms_output.put_line('error!');
end;
/
执行上面示例代码,得到以下结果 -
上面的程序用于显示指定id的客户的名字和地址。但是由于数据库customers
表中并没有id
值为100
的客户,因此程序引发异常,并在exception
块中捕获的运行时异常no_data_found
,因此最后打印了信息:‘没有找到符合条件的客户信息!’。
只要有内部数据库错误,数据库服务器就会自动产生(引发)异常,但程序员可以使用命令raise
明确地引发异常。以下是引发异常的简单语法 -
declare
exception_name exception;
begin
if condition then
raise exception_name;
end if;
exception
when exception_name then
statement;
end;
可以使用上述语法来引发oracle标准异常或任何用户定义的异常。 在下一节中,我们将举例说明引发用户定义的异常。您可以用类似的方式引发oracle中标准异常。
pl/sql允许根据程序的需要定义自己的异常。 用户定义的异常必须声明,然后使用raise
语句或过程dbms_standard.raise_application_error
显式地引发。
声明异常的语法是 -
declare
my-exception exception;
以下示例说明了这个概念。这个程序要求输入一个客户id,当用户输入一个无效的id时,会引发异常invalid_id
。参考以下示例代码的实现 -
set serveroutput on size 9999;
declare
c_id customers.id%type := &cc_id;
c_name customers.name%type;
c_addr customers.address%type;
-- user defined exception
ex_invalid_id exception;
begin
if c_id <= 0 then
raise ex_invalid_id;
else
select name, address into c_name, c_addr
from customers
where id = c_id;
dbms_output.put_line ('姓名: '|| c_name);
dbms_output.put_line ('地址: ' || c_addr);
end if;
exception
when ex_invalid_id then
dbms_output.put_line('编号id必须要大于0!');
when no_data_found then
dbms_output.put_line('未找到指定id的客户信息!');
when others then
dbms_output.put_line('error!');
end;
/
执行上面示例代码,得到以下结果 -
输入 cc_id 的值: -1
原值 2: c_id customers.id%type := &cc_id;
新值 2: c_id customers.id%type := -1;
编号id必须要大于0!
pl/sql 过程已成功完成。
pl/sql提供了许多预定义的异常,这些异常在程序违反任何数据库规则时执行。 例如,当select into
语句不返回任何行时,会引发预定义的异常no_data_found
。下表列出了一些重要的预定义异常情况 -
异常 | oracle错误代码 | sqlcode | 描述 |
---|---|---|---|
access_into_null |
06530 | -6530 |
当一个空对象被自动分配一个值时会引发它。 |
case_not_found |
06592 | -6592 |
当没有选择case 语句的when 子句中的任何选项时,会引发这个错误,并且没有else 子句。 |
collection_is_null |
06531 | -6531 |
当程序尝试将exists 以外的集合方法应用于未初始化的嵌套表或varray 时,或程序尝试将值分配给未初始化的嵌套表或varray 的元素时,会引发此问题。 |
dup_val_on_index |
00001 | -1 |
当尝试将重复值存储在具有唯一索引的列中时引发此错误。 |
invalid_cursor |
01001 | -1001 |
当尝试进行不允许的游标操作(例如关闭未打开的游标)时会引发此错误。 |
invalid_number |
01722 | -1722 |
当字符串转换为数字时失败,因为字符串不代表有效的数字。 |
login_denied |
01017 | -1017 |
当程序尝试使用无效的用户名或密码登录到数据库时引发。 |
no_data_found |
01403 | +100 |
当select into 语句不返回任何行时会引发它。 |
not_logged_on |
01012 | -1012 |
当数据库调用没有连接到数据库时引发。 |
program_error |
06501 | -6501 |
当pl/sql遇到内部问题时会引发。 |
rowtype_mismatch |
06504 | -6504 |
当游标在具有不兼容数据类型的变量中获取值时引发。 |
self_is_null |
30625 | -30625 |
当调用成员方法时引发,但对象类型的实例未初始化。 |
storage_error |
06500 | -6500 |
当pl/sql用尽内存或内存已损坏时引发。 |
too_many_rows |
01422 | -1422 |
当select into 语句返回多行时引发。 |
value_error |
06502 | -6502 |
当发生算术,转换,截断或者sizeconstraint 错误时引发。 |
zero_divide |
01476 | 1476 |
当尝试将数字除以零时引发。 |