Postgresql触发器实现对表的日志审计

1. 创建日志表与触发器函数

复制代码
-- 1. 创建通用日志表
CREATE TABLE t_case_log (
    log_id BIGSERIAL PRIMARY KEY,
    case_id BIGINT,
    operation VARCHAR(10), -- INSERT, UPDATE, DELETE
    old_data JSONB,        -- 修改/删除前的数据
    new_data JSONB,        -- 新增/修改后的数据
    changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    changed_by VARCHAR(50) DEFAULT CURRENT_USER
);

-- 2. 创建触发器函数
CREATE OR REPLACE FUNCTION process_t_case_audit()
RETURNS TRIGGER AS $$
BEGIN
    IF (TG_OP = 'DELETE') THEN
        INSERT INTO t_case_log(case_id, operation, old_data)
        VALUES (OLD.id, 'DELETE', to_jsonb(OLD));
        RETURN OLD;
    ELSIF (TG_OP = 'UPDATE') THEN
        INSERT INTO t_case_log(case_id, operation, old_data, new_data)
        VALUES (NEW.id, 'UPDATE', to_jsonb(OLD), to_jsonb(NEW));
        RETURN NEW;
    ELSIF (TG_OP = 'INSERT') THEN
        INSERT INTO t_case_log(case_id, operation, new_data)
        VALUES (NEW.id, 'INSERT', to_jsonb(NEW));
        RETURN NEW;
    END IF;
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;

-- 3. 将触发器绑定到 t_case 表
CREATE TRIGGER t_case_audit_trigger
AFTER INSERT OR UPDATE OR DELETE ON t_case
FOR EACH ROW EXECUTE FUNCTION process_t_case_audit();

2. 查询审计日志

直接在 PostgreSQL 执行 SQL 或通过 Spring Data JPA 映射 t_case_log 进行查询:

复制代码
SELECT * FROM t_case_log WHERE case_id = 1001 ORDER BY changed_at DESC;

这段 SQL 脚本实现了一个数据库层面的自动数据审计机制 。当对 t_case 表执行新增、修改或删除(CUD)时,PostgreSQL 会自动捕获数据变动,并将变更前后的完整快照以 JSON 格式写入 t_case_log 日志表。

一、 审计日志表设计 (t_case_log)

  • log_id :日志主键,使用 BIGSERIAL 实现自增。

  • case_id:关联的目标记录 ID。

  • operation :记录操作类型,仅包含 INSERT、UPDATE、DELETE 三种。

  • old_data / new_data :核心设计,采用 PostgreSQL 的 JSONB 类型。直接将整行数据转为 JSON 存储,优势在于即便将来 t_case 表增删字段,该日志表结构也无需任何修改。

  • changed_at / changed_by :利用数据库默认值(CURRENT_TIMESTAMP 和 CURRENT_USER)自动记录变动发生的时间与数据库操作账号。

二、 触发器函数逻辑 (process_t_case_audit)

函数基于 PL/pgSQL 编写,利用了 PostgreSQL 的内置触发器变量:

  • 内置变量解析:

    • TG_OP :存储触发当前函数的 SQL 类型(INSERT / UPDATE / DELETE)。

    • OLD :代表变更或删除前 的整行记录(仅在 UPDATE 和 DELETE 时可用)。

    • NEW :代表新增或修改后 的整行记录(仅在 INSERT 和 UPDATE 时可用)。

    • to_jsonb(...):PG 内置函数,直接将一行 Row 记录转换为 JSONB 对象。

  • 分流逻辑:

    • DELETE :仅提取并记录 OLD 数据(删除前的快照)。

    • UPDATE :同时记录 OLD(修改前)和 NEW(修改后),方便后期做属性级别的差异对比(Diff)。

    • INSERT :仅提取并记录 NEW 数据(新插入的数据)。

三、 绑定触发器 (t_case_audit_trigger)

  • AFTER INSERT OR UPDATE OR DELETE :采用 事后触发(AFTER) 。只有在 t_case 的数据修改成功后才会写入日志;若主语句因约束等原因报错回滚,日志写入也会同步回滚,确保审计数据的绝对真实性。

  • FOR EACH ROW:行级触发器。如果是批量修改(例如一条 SQL 更新了 10 条记录),函数会被调用 10 次,生成 10 条精准的日志。

💡 实际落地时的注意事项

  1. 应用层操作人问题 : changed_by 默认记录的是 PG 的数据库连接用户(如 postgres)。如果是 Spring Boot 应用通过连接池操作,这里记录的永远是连接池账号,无法体现"系统登录的具体用户" 。如果需要记录业务用户 ID,通常需要配合 PG 的临时变量(SET LOCAL app.current_user_id = 'xxx')或在应用层(如 Hibernate Envers / AOP)处理。

  2. 写性能开销 : 由于是 AFTER ... FOR EACH ROW 触发器,每一次对 t_case 的写入都会同步带来一次对 t_case_log 的写入(1:1 写放大)。在大批量数据导入或高并发写入场景下,需注意评估 IO 负载。

相关推荐
Leo.yuan1 小时前
2026企业级数据集成平台市场报告:国内外厂商格局与技术路线
数据库·oracle
guo_wen_qiang2 小时前
云服务器mysql分库分表环境搭建(2库4表)
数据库·mysql·docker
jianpeng的工程笔记2 小时前
EL8 / EL9 安装 Slurm 26.05.4:主备控制器、MariaDB 记账与作业验收
linux·数据库·mariadb·高性能计算·slurm
SelectDB技术团队2 小时前
ClickHouse 存日志的能力边界:并发、检索与 trace 回放的实测对照
数据结构·数据库·clickhouse·日志分析·apache doris·日志存储
倔强的小石头_2 小时前
Ubuntu部署Prometheus与Alertmanager:systemd配置、告警对接及cpolar远程访问
数据库·ubuntu·prometheus
茉莉玫瑰花茶2 小时前
GO [ 接口 ]
服务器·数据库·golang
babe小鑫2 小时前
金融工程专业秋招:金融类证书与数据分析类证书的搭配方案
大数据·数据库·人工智能
User_芊芊君子3 小时前
数据库手记:从数据建模到 Spark 对接的实测记录
大数据·数据库·spark
꯭自꯭闭꯭3 小时前
DM主备集群以及读写分离集群搭建
linux·运维·数据库