想象一下,你写了个函数用来算学生的平均分。如果你试图除以零(比如没有成绩的时候)会发生啥?你把这样的代码放到生产环境——bug就会突然冒出来。PL/pgSQL给了我们强大的错误处理工具,让你的代码更健壮、更安全、用起来也更爽。
PL/pgSQL里的错误处理可以:
- 生成消息,告诉你哪里出错了。
- 在遇到严重错误时终止代码执行。
- 把问题记录下来,方便以后分析。
PL/pgSQL的主要消息级别
PL/pgSQL支持好几种消息级别,帮开发者高效定位和解决问题。主要有这些:
- NOTICE:输出信息性消息。一般用来调试。
- WARNING:提示有潜在问题,但不会中断程序。
- EXCEPTION:严重错误,会中断程序(并把控制权交还给调用方)。
PL/pgSQL的消息级别
| 消息级别 | 描述 |
|---|---|
NOTICE |
信息或调试消息。不会影响执行 |
WARNING |
可能有问题的警告。就像个小提示 |
EXCEPTION |
严重错误,会终止程序执行 |
RAISE语句的语法
用RAISE操作符可以生成消息和处理错误。基本语法如下:
RAISE <消息级别> '消息文本' [, 变量...];
<消息级别>—NOTICE、WARNING、EXCEPTION。'消息文本'— 问题描述。[变量...]— 可以传给消息文本的额外值。
例1:用RAISE NOTICE
有时候你得知道函数内部发生了啥。比如调试循环:
DO $$
BEGIN
FOR i IN 1..5 LOOP
RAISE NOTICE '当前i的值: %', i;
END LOOP;
END
$$;
结果:控制台会输出当前i的值: 1、当前i的值: 2,一直到5。
例2:用RAISE EXCEPTION
现在假设你写了个函数,遇到某些条件就得报错退出:
DO $$
BEGIN
IF 1 = 1 THEN
RAISE EXCEPTION '出问题啦!';
END IF;
END
$$;
结果:执行被中断,错误消息会显示在控制台。
在RAISE里用参数
用参数可以让消息更个性化。用%占位符就行:
例3:在RAISE里插入变量
DO $$
DECLARE
student_name TEXT := '伊万';
average_score NUMERIC := NULL;
BEGIN
IF average_score IS NULL THEN
RAISE EXCEPTION '学生 % 没有平均分!', student_name;
END IF;
END
$$;
结果:消息学生 伊万 没有平均分!。
你看,%会被student_name变量替换,让消息更有意义。
自定义错误
错误不只是意外!有时候你得故意抛出来,防止数据出错。
例4:检查输入值
写个函数,检查输入的数字,如果是负数就报错:
CREATE OR REPLACE FUNCTION check_positive(value NUMERIC)
RETURNS TEXT AS $$
BEGIN
IF value < 0 THEN
RAISE EXCEPTION '数字 % 是负数!', value;
END IF;
RETURN '数字没问题。';
END;
$$ LANGUAGE plpgsql;
现在来测试下这个函数:
SELECT check_positive(-5);
结果:错误消息数字 -5 是负数!。
如果传正数:
SELECT check_positive(10);
结果:数字没问题。
上下文中的错误处理
你会抛错当然不错,但能根据情况处理错误就更牛了。用BEGIN ... EXCEPTION块就能做到。
错误处理结构
BEGIN
-- 你的主代码
EXCEPTION
WHEN 错误类型 THEN
-- 出错时要做啥
WHEN 另一个错误 THEN
-- 另一个错误时的操作
WHEN OTHERS THEN
-- 处理所有其他错误
END;
来解释下各部分:
EXCEPTION— 关键字,表示错误处理块开始。WHEN— 指定要处理的具体错误类型,比如unique_violation或division_by_zero。OTHERS— 处理所有没被明确写出来的错误。
例5:处理除零错误
举个简单的除法函数来演示错误处理:
CREATE OR REPLACE FUNCTION safe_divide(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
-- 尝试做除法
RETURN a / b;
EXCEPTION
WHEN division_by_zero THEN
RAISE WARNING '试图除以零。返回NULL。';
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
测试下这个函数:
SELECT safe_divide(10, 2); -- 预期结果: 5
SELECT safe_divide(10, 0); -- 预期结果: NULL,控制台有警告
用RAISE时常见的坑
忘记写消息级别。 如果你没写级别,PostgreSQL会报错。
错的写法:
RAISE '没有级别的消息';
对的写法:
RAISE NOTICE '有NOTICE级别的消息';
参数不对。 用了%,记得要传够变量。
错的写法:
RAISE NOTICE '带参数的例子 %';
对的写法:
RAISE NOTICE '带参数的例子 %', '值';
用太多RAISE EXCEPTION。 乱用RAISE EXCEPTION会让重要操作被中断。要用得有分寸。
实用建议
- 用
WHEN OTHERS要小心。 能具体写错误类型就别全用OTHERS,避免把本该特殊处理的错误都拦了。 - 用
RAISE来调试。 千万别让错误没人管。 - 别忘了性能。 错误处理会有点性能损耗,尤其在大存储过程里。
只要你用对了,存储过程就会很坚挺,哪怕遇到奇葩bug也不怕。PM看到会超骄傲的!
GO TO FULL VERSION