PL/SQL 异常处理(Exception Handling)¶
本章系统讲解 PL/SQL 的异常处理机制。异常处理是保证数据库程序稳定性和数据一致性的关键内容,在金融/账务/请求书系统等项目以及面试中都属于高频重点。
1. 异常处理概述¶
异常(Exception)是指程序在运行过程中发生的错误或非正常情况。 PL/SQL 提供了完善的异常处理机制,用于:
- 捕获运行时错误
- 避免程序异常中断
- 记录错误信息
- 将错误转换为业务可识别的结果
PL/SQL 异常分为三类:
| 分类 | 说明 |
|---|---|
| 预定义异常 | Oracle 预先定义的常见异常 |
| 非预定义异常 | Oracle 错误码,但未定义名称 |
| 用户自定义异常 | 业务层自定义异常 |
2. 异常处理基本结构¶
异常处理块位于 PL/SQL 块的 EXCEPTION 区域。
begin
-- 正常处理逻辑
exception
when exception_name then
-- 异常处理逻辑
end;
/
⚠️ 注意:
- 异常一旦发生,BEGIN 中剩余语句不会再执行
- 程序直接跳转到 EXCEPTION 区域
3. 常见预定义异常(面试必背)¶
| 异常名 | 触发场景 |
|---|---|
| NO_DATA_FOUND | SELECT INTO 查询结果为 0 行 |
| TOO_MANY_ROWS | SELECT INTO 查询结果大于 1 行 |
| DUP_VAL_ON_INDEX | 唯一索引/主键冲突 |
| ZERO_DIVIDE | 除数为 0 |
| VALUE_ERROR | 类型转换或长度错误 |
| INVALID_NUMBER | 字符串转数字失败 |
示例:NO_DATA_FOUND¶
declare
v_name emp.ename%type;
begin
select ename into v_name
from emp
where empno = 9999;
exception
when no_data_found then
dbms_output.put_line('No data found');
end;
/
4. WHEN OTHERS(兜底异常)¶
WHEN OTHERS 用于捕获 所有未被显式处理的异常。
exception
when others then
dbms_output.put_line('Error occurred');
end;
❌ 错误示范(面试减分)¶
exception
when others then
null;
end;
⚠️ 问题:
- 吞掉异常
- 难以排查问题
✅ 正确示范(项目推荐)¶
exception
when others then
dbms_output.put_line('Error code=' || sqlcode);
dbms_output.put_line('Error msg=' || sqlerrm);
raise;
end;
5. 非预定义异常(使用 PRAGMA EXCEPTION_INIT)¶
当 Oracle 抛出的错误没有预定义异常名时,可以手动绑定错误码。
declare
e_fk_violation exception;
pragma exception_init(e_fk_violation, -2292);
begin
delete from dept where deptno = 10;
exception
when e_fk_violation then
dbms_output.put_line('Cannot delete: child record exists');
end;
/
6. 用户自定义异常(业务异常)¶
用户自定义异常用于表示 业务规则错误。
定义并抛出异常¶
declare
e_limit_exceeded exception;
v_amount number := 20000;
begin
if v_amount > 10000 then
raise e_limit_exceeded;
end if;
exception
when e_limit_exceeded then
dbms_output.put_line('Amount exceeds limit');
end;
/
7. RAISE_APPLICATION_ERROR(项目必用)¶
RAISE_APPLICATION_ERROR 用于向调用方返回 明确的业务错误码和错误信息。
raise_application_error(
-20001,
'Balance is not enough'
);
业务化示例¶
if v_balance < v_amount then
raise_application_error(
-20002,
'Insufficient balance'
);
end if;
📌 约定:
- 错误码范围:-20001 ~ -20999
- Java / Batch / 前端统一解析
8. 异常与事务的关系¶
- PL/SQL 中 异常不会自动回滚事务
- 是否回滚,取决于程序中是否显式
ROLLBACK
begin
update account set balance = balance - 100 where id = 1;
update account set balance = balance + 100 where id = 2;
exception
when others then
rollback;
raise;
end;
/
9. 日志记录与自治事务¶
在项目中,即使主事务失败,也需要记录日志,可使用自治事务。
create or replace procedure p_log(p_msg varchar2) is
pragma autonomous_transaction;
begin
insert into t_error_log(msg, log_time)
values(p_msg, systimestamp);
commit;
end;
/
调用示例:
exception
when others then
p_log(sqlcode || ':' || sqlerrm);
rollback;
raise;
end;
10. 项目实践总结(非常重要)¶
- 精确捕获已知异常(NO_DATA_FOUND 等)
- WHEN OTHERS 必须记录日志并重新抛出
- 业务异常使用 RAISE_APPLICATION_ERROR
- 异常处理与事务控制必须配合设计
11. 本章小结¶
- PL/SQL 通过 EXCEPTION 区块处理异常
- SELECT INTO 常见异常:NO_DATA_FOUND / TOO_MANY_ROWS
- WHEN OTHERS 只能兜底,不能吞异常
- 使用 RAISE_APPLICATION_ERROR 返回业务错误
- 项目中通常配合日志与自治事务使用