CodeGym /课程 /SQL SELF /通过函数实现自动日志记录

通过函数实现自动日志记录

SQL SELF
第 52 级 , 课程 3
可用

通过函数实现自动日志记录

想象一下,你让你的bot在数据库里自由发挥,执行各种复杂操作。迟早它会出错、犯傻,或者遇到意外情况。如果没有日志记录,它可能直接沉默,你就会一脸懵逼,不知道哪里出问题了。自动日志记录能帮你:

  • 追踪错误和警告的发生。
  • 搞清楚故障的本质和原因。
  • 让代码更好调试和优化。

用自动日志记录,你就有了一个“黑匣子”,能把数据库里的事件都记下来,帮你像侦探一样找bug。

用函数实现自动日志记录

  1. 定义日志表

要记录错误,得有地方存。我们在上一节已经建过error_log表:

CREATE TABLE error_log (
    id SERIAL PRIMARY KEY,                 -- 唯一记录ID
    error_message TEXT NOT NULL,          -- 错误信息
    error_time TIMESTAMP DEFAULT NOW(),   -- 错误发生时间
    function_name TEXT                    -- 抛出错误的函数名
);

这个表有记录错误需要的所有东西:错误文本、时间和出错的函数。

  1. 写一个日志记录函数

下一步——写一个通用函数,把错误写进error_log表。每次你想记录错误时就调用它。

CREATE OR REPLACE FUNCTION log_error(p_error_message TEXT, p_function_name TEXT)
RETURNS VOID AS $$
BEGIN
    INSERT INTO error_log (error_message, function_name)
    VALUES (p_error_message, p_function_name);
    -- 日志记录成功的提示
    RAISE NOTICE 'Error logged: %', p_error_message;
END;
$$ LANGUAGE plpgsql;

来拆解下这段代码:

  1. p_error_messagep_function_name是函数参数,分别接收错误信息和出错函数名。
  2. INSERT INTO error_log把记录插进表里。
  3. RAISE NOTICE会在控制台输出提示,让开发者知道日志已经写入。

现在我们搞定了第一步:可以很方便地把错误写进表里了。

在实际任务中用log_error函数

例子1:除零错误日志

写个函数做简单的除法,如果分母是0就记录错误。

CREATE OR REPLACE FUNCTION divide_numbers(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
    result NUMERIC;
BEGIN
    IF b = 0 THEN
        -- 调用日志函数
        PERFORM log_error('尝试除以零!', 'divide_numbers');
        -- 抛出异常
        RAISE EXCEPTION '不允许除以零。';
    END IF;

    -- 执行除法
    result := a / b;
    RETURN result;
END;
$$ LANGUAGE plpgsql;
  • 如果分母是0,会调用log_error,把错误写进表里。
  • 写完日志后用RAISE EXCEPTION抛出异常,提醒用户。

调用例子:

SELECT divide_numbers(10, 0);

结果:

  • 用0做除法会在error_log表里写一条错误记录。
  • 用户会在控制台看到错误提示。

例子2:插入无效数据时的日志

比如有个函数往students表加新学生。如果名字是空的,我们就写日志并终止执行。

CREATE OR REPLACE FUNCTION add_student(p_name TEXT)
RETURNS VOID AS $$
BEGIN
    IF p_name IS NULL OR p_name = '' THEN
        PERFORM log_error('必须填写学生姓名!', 'add_student');
        RAISE EXCEPTION '学生姓名不能为空。';
    END IF;

    INSERT INTO students (name) VALUES (p_name);
END;
$$ LANGUAGE plpgsql;

调用例子:

SELECT add_student('');

如果你试图加个没名字的学生,函数会在error_log里写一条记录。

例子3:记录警告日志

有时候不用抛异常,只要记个警告就行。比如写个函数检查学生年龄:

CREATE OR REPLACE FUNCTION check_age(p_age INT)
RETURNS VOID AS $$
BEGIN
    IF p_age < 18 THEN
        -- 记录警告但不中断
        PERFORM log_error('学生年龄小于18。', 'check_age');
        RAISE NOTICE '警告:学生年龄小于18。';
    END IF;

    RAISE NOTICE '年龄检查通过。';
END;
$$ LANGUAGE plpgsql;

调用例子:

SELECT check_age(16);

结果:

  • error_log表里写一条警告。
  • 控制台会提示学生年龄小于18。

日志记录和异常处理

我们来把错误记录和异常处理结合起来,写个复杂点的函数。比如要给grades表里的学生重新算分。如果某个学生失败了,记录错误但继续处理其他人。

CREATE OR REPLACE FUNCTION recalculate_grades()
RETURNS VOID AS $$
DECLARE
    student RECORD;
BEGIN
    FOR student IN SELECT * FROM students LOOP
        BEGIN
            -- 例子:更新学生成绩
            UPDATE grades SET final_grade = final_grade + 1
            WHERE student_id = student.id;

            RAISE NOTICE '已更新学生%成绩', student.name;
        EXCEPTION WHEN OTHERS THEN
            -- 记录错误并继续
            PERFORM log_error('无法更新学生' || student.name || '的成绩', 'recalculate_grades');
        END;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

调用例子:

SELECT recalculate_grades();

这样你的函数就更健壮了,错误会单独记录,不会让所有数据都停下来。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION