咱们现在就像秘密特工一样——我们的函数和过程在执行任务:处理数据、做计算,或者在数据库里搞点小魔法。但要是哪里出错了咋办?怎么知道“数据按摩浴缸”在哪个阶段坏掉了?这时候就得靠日志记录和错误处理来帮忙了。
还记得我们之前聊过,在PostgreSQL和PL/pgSQL里怎么“交流”和写日志吗:
RAISE NOTICE:语气很温和,像在说“嘿,一切都OK,不过你可能想看看这个”。RAISE WARNING:语气稍微大点声——“哎,这里有点怪,你要不要瞅一眼”。RAISE EXCEPTION:警报拉响——“停!算法出事了!我们把执行停了,免得一切都崩了”。
每个级别都有自己的用处,选对很重要。
这些消息在代码里长这样:
DO $$
BEGIN
-- NOTICE级别(没事,就是通知一下)
RAISE NOTICE '只是通知:数据处理开始了';
-- WARNING级别(有点可疑)
RAISE WARNING '警告:列里的数据格式可能不对';
-- EXCEPTION级别(严重错误)
RAISE EXCEPTION '错误:输入值不合法!';
END $$;
啥时候用:
RAISE NOTICE—— 用来调试和输出普通信息。RAISE WARNING—— 提醒有可能数据不对。RAISE EXCEPTION—— 真出大事了,必须停下函数执行。
用RAISE EXCEPTION处理错误
RAISE EXCEPTION就是你的紧急刹车。要是哪儿不对劲,你可以直接停掉函数执行并报错。
最基本的用法是这样的:
RAISE EXCEPTION '你的错误消息';
不过想让消息更有用,可以用变量:
DECLARE
input_value INTEGER;
BEGIN
input_value := NULL;
IF input_value IS NULL THEN
RAISE EXCEPTION '错误:输入值是NULL。应该是INTEGER类型';
END IF;
END;
消息格式化
你可以直接把变量插进消息里:
DECLARE
var1 TEXT := '数据';
var2 INTEGER := 42;
BEGIN
RAISE EXCEPTION '处理%时出错,ID为%', var1, var2;
END;
输出:处理数据时出错,ID为42。
例子:数据校验
假如你有个过程,接收人的年龄。如果年龄是负数,肯定要报错:
CREATE OR REPLACE FUNCTION validate_age(age INTEGER)
RETURNS VOID AS $$
BEGIN
IF age < 0 THEN
RAISE EXCEPTION '年龄不能为负数:%', age;
END IF;
END;
$$ LANGUAGE plpgsql;
-- 调用函数
SELECT validate_age(-5); -- 会报错
用RAISE NOTICE做信息提示
如果说RAISE EXCEPTION是警报,那RAISE NOTICE就是拍拍肩膀的提醒。用这个级别可以加点注释,让大家知道函数里发生了啥。
啥时候用RAISE NOTICE:
- 输出调试信息(比如变量当前值)。
- 提示某个阶段开始执行或者计算结果。
例子:信息提示
CREATE OR REPLACE FUNCTION calculate_discount(price NUMERIC, discount_rate NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
final_price NUMERIC;
BEGIN
RAISE NOTICE '打折前价格:%', price;
RAISE NOTICE '折扣率:%', discount_rate;
final_price := price - (price * discount_rate);
RAISE NOTICE '最终价格:%', final_price;
RETURN final_price;
END;
$$ LANGUAGE plpgsql;
-- 调用函数
SELECT calculate_discount(100, 0.2);
-- 输出:
-- NOTICE: 打折前价格:100
-- NOTICE: 折扣率:0.2
-- NOTICE: 最终价格:80
实战:规划和日志记录
假如你有个很复杂的数据处理过程,你想知道现在执行到哪一步了:
CREATE OR REPLACE FUNCTION process_data_step_by_step()
RETURNS VOID AS $$
BEGIN
RAISE NOTICE '步骤1:准备数据';
-- 第一步的逻辑
RAISE NOTICE '步骤2:校验数据';
-- 第二步的逻辑
RAISE NOTICE '步骤3:保存数据';
-- 第三步的逻辑
END;
$$ LANGUAGE plpgsql;
-- 调用函数
SELECT process_data_step_by_step();
-- 日志里会显示每一步
再举个例子。 假设有个商店,只有订单金额超过某个数才给打折:
CREATE OR REPLACE FUNCTION apply_discount(order_amount NUMERIC)
RETURNS NUMERIC AS $$
BEGIN
IF order_amount < 50 THEN
RAISE EXCEPTION '错误:订单金额必须不少于50,当前金额:%', order_amount;
END IF;
RETURN order_amount * 0.9; -- 打九折
END;
$$ LANGUAGE plpgsql;
-- 调用函数
SELECT apply_discount(30); -- 错误:订单金额必须不少于50
常见错误
错误1:日志消息没带参数。
这样在大过程里看起来很没用:
RAISE NOTICE '发生了错误'; -- 为什么?哪儿?怎么回事?
建议:一定要加点上下文:
RAISE NOTICE 'process_data()函数出错:输入值为%', input_value;
错误2:用RAISE EXCEPTION的地方其实用RAISE WARNING就够了。
如果你老是抛异常,代码会动不动就停,数据处理会很麻烦。
建议:日志级别要用得明白。调试用NOTICE,真出大事才用EXCEPTION。
错误3:完全不写日志。
这就像在黑屋子里找钥匙。没有日志,复杂流程根本没法调试。
建议:在函数关键步骤加RAISE NOTICE,尤其是大函数和复杂逻辑。
GO TO FULL VERSION