Oracle中自定义异常内置异常嵌套异常的捕获处理

一、异常类型分类

类型说明示例
内置预定义异常Oracle已命名异常(如NO_DATA_FOUND)查询无数据时触发
内置非预定义异常未命名的Oracle错误(需用PRAGMA EXCEPTION_INIT关联)ORA-02290(违反检查约束)
自定义异常用户定义的业务逻辑异常数据校验失败时手动抛出

二、异常处理语法
1. 基本结构

DECLARE
  -- 声明自定义异常
  custom_exception EXCEPTION;
  -- 绑定错误代码到非预定义异常
  PRAGMA EXCEPTION_INIT(custom_exception, -20001);
BEGIN
  -- 业务逻辑
  IF 条件 THEN
    RAISE custom_exception; -- 手动抛出异常
  END IF;
EXCEPTION
  WHEN custom_exception THEN
    DBMS_OUTPUT.PUT_LINE('自定义异常触发');
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('数据未找到');
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('错误代码: ' || SQLCODE);
    DBMS_OUTPUT.PUT_LINE('错误信息: ' || SQLERRM);
END;

三、异常语法
1. 自定义异常
步骤说明:

①声明异常:

DECLARE
  invalid_salary EXCEPTION;

②关联错误代码(可选):

PRAGMA EXCEPTION_INIT(invalid_salary, -20001);

③抛出异常:

IF salary < 0 THEN
  RAISE invalid_salary;
END IF;

④捕获处理:

EXCEPTION
  WHEN invalid_salary THEN
    DBMS_OUTPUT.PUT_LINE('薪资不能为负数');

2. 内置异常处理
常用预定义异常:
NO_DATA_FOUND: SELECT未找到数据
TOO_MANY_ROWS: SELECT返回多行数据
ZERO_DIVIDE: 除数为零
DUP_VAL_ON_INDEX: 唯一索引冲突

-- 示例:
BEGIN
  SELECT * INTO emp_rec FROM emp WHERE emp_id = 999;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('员工ID不存在');
  WHEN TOO_MANY_ROWS THEN
    DBMS_OUTPUT.PUT_LINE('返回多行数据');
END;

3. 嵌套异常处理
结构示例:

DECLARE
  outer_exception EXCEPTION;
BEGIN
  <<inner_block>>
  DECLARE
    inner_exception EXCEPTION;
  BEGIN
    RAISE inner_exception;
  EXCEPTION
    WHEN inner_exception THEN
      DBMS_OUTPUT.PUT_LINE('内部异常已处理');
      RAISE outer_exception; -- 抛出到外层
  END inner_block;
EXCEPTION
  WHEN outer_exception THEN
    DBMS_OUTPUT.PUT_LINE('外部捕获到异常');
END;

详细实例:

DECLARE
  -- 定义变量和异常
  v_employee_id employees.employee_id%TYPE := 100;
  v_salary employees.salary%TYPE;
  e_negative_salary EXCEPTION; -- 自定义异常:工资为负
  PRAGMA EXCEPTION_INIT(e_negative_salary, -20001); -- 绑定错误代码
BEGIN
  -- 外层块
  BEGIN -- 内层块开始
    -- 尝试获取员工工资
    SELECT salary INTO v_salary 
    FROM employees 
    WHERE employee_id = v_employee_id;

    -- 模拟业务逻辑:检查工资有效性
    IF v_salary < 0 THEN
      RAISE_APPLICATION_ERROR(-20001, '工资不能为负数'); -- 触发自定义异常
    END IF;

    DBMS_OUTPUT.PUT_LINE('内层块:工资处理成功。');

  EXCEPTION -- 内层异常处理
    WHEN NO_DATA_FOUND THEN
      DBMS_OUTPUT.PUT_LINE('内层块:员工ID ' || v_employee_id || ' 不存在。');
      RAISE; -- 重新抛出到外层
    WHEN e_negative_salary THEN
      DBMS_OUTPUT.PUT_LINE('内层块:异常 - ' || SQLERRM);
      -- 此处可添加恢复逻辑,如设置默认工资
      v_salary := 0;
      DBMS_OUTPUT.PUT_LINE('内层块:工资已重置为0。');
  END; -- 内层块结束

  -- 外层业务逻辑(内层未异常终止时执行)
  DBMS_OUTPUT.PUT_LINE('外层块:更新后工资为 ' || v_salary);

EXCEPTION -- 外层异常处理
  WHEN NO_DATA_FOUND THEN
    DBMS_OUTPUT.PUT_LINE('外层块:错误 - 指定员工不存在。');
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('外层块:未知错误 - ' || SQLERRM);
    ROLLBACK; -- 示例事务回滚
END;

嵌套结构:

  • 内层块: 处理具体数据库操作(如查询、业务验证),捕获NO_DATA_FOUND(预定义)和自定义异常。
  • 外层块: 处理内层未处理的异常,执行后续业务逻辑或全局错误处理。

异常传播:

  • 内层处理并解决: 如e_negative_salary异常被捕获后重置工资,程序继续执行外层代码。
  • 内层重新抛出: NO_DATA_FOUND在内层处理后通过RAISE传递到外层,触发外层对应处理程序。

自定义异常:

  • 使用RAISE_APPLICATION_ERROR抛出并关联错误代码,PRAGMA
    EXCEPTION_INIT将自定义异常绑定到特定错误号。

事务控制:

  • 外层异常处理中可包含ROLLBACK,确保数据一致性(根据实际业务需求调整)。

嵌套规则:

  • 内部块未处理的异常会自动传递到外层块
  • 使用RAISE可手动将异常传递到上层

四、其他处理
1. 错误日志记录

EXCEPTION
  WHEN OTHERS THEN
    INSERT INTO error_log (code, message, time)
    VALUES (SQLCODE, SQLERRM, SYSDATE);
    COMMIT;
    RAISE; -- 继续向上层传递异常
END;

2. 动态错误消息

RAISE_APPLICATION_ERROR(-20001, '订单 ' || order_id || ' 状态无效');

3. 异常传播控制

BEGIN
  -- 业务逻辑
EXCEPTION
  WHEN OTHERS THEN
    IF SQLCODE = -2290 THEN
      DBMS_OUTPUT.PUT_LINE('约束违反');
    ELSE
      RAISE; -- 继续传播未明确处理的异常
    END IF;
END;

五、总结
优先级处理:

EXCEPTION
  WHEN NO_DATA_FOUND THEN ... -- 特定异常在前
  WHEN OTHERS THEN ...        -- 通用处理在后

事务控制:

BEGIN
  SAVEPOINT sp1;
  -- DML操作
EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK TO sp1;
    RAISE;
END;

错误代码规范:

  • 自定义错误代码范围:-20000 到 -20999
  • 统一错误消息格式

通过合理使用异常处理机制,可显著提升Oracle程序的健壮性。建议在复杂业务逻辑中优先定义清晰的异常处理策略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值