CodeGym /课程 /SQL SELF /错误日志记录:日志级别和消息格式

错误日志记录:日志级别和消息格式

SQL SELF
第 55 级 , 课程 2
可用

咱们现在就像秘密特工一样——我们的函数和过程在执行任务:处理数据、做计算,或者在数据库里搞点小魔法。但要是哪里出错了咋办?怎么知道“数据按摩浴缸”在哪个阶段坏掉了?这时候就得靠日志记录和错误处理来帮忙了。

还记得我们之前聊过,在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,尤其是大函数和复杂逻辑。

2
任务
SQL SELF, 第 55 级, 课程 2
已锁定
数据校验时的错误日志记录
数据校验时的错误日志记录
评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION