解析PostgreSQL触发器记录数据库操作的SQL语句

news/2024/7/8 3:54:41

引言

在数据库操作中,跟踪和记录执行的 SQL 语句对于调试和审计非常重要。本篇博客将介绍如何使用 PostgreSQL 触发器来记录数据库操作的 SQL 语句,并提供一个解决方案。

问题背景

在许多应用程序中,我们经常需要了解数据库中执行的 SQL 语句,以便追踪和监控应用的行为。然而,仅仅依赖应用程序日志并不能提供完整的信息,特别是在多个客户端或多个应用程序同时对数据库进行操作的情况下。

解决方案

为了解决这个问题,我们可以使用 PostgreSQL 的触发器功能。触发器是一种在数据库操作之前或之后自动执行的函数。通过创建一个触发器,我们可以捕获并记录数据库操作的 SQL 语句。

以下是解决方案的步骤:

  1. 创建一个日志表:首先,我们需要创建一个用于存储操作日志的表。该表应包含列来存储时间戳、用户名、操作类型和 SQL 语句。下面是一个示例的表结构:

DROP TABLE IF EXISTS "tb_sys_operation_log";
CREATE TABLE "tb_sys_operation_log" (
  "id" SERIAL PRIMARY KEY,
  "operation_type" varchar(50) COLLATE "pg_catalog"."default",
  "operation_tablename" varchar(50) COLLATE "pg_catalog"."default",
  "sql_statement" text COLLATE "pg_catalog"."default",
  "operation_pid" int4 ,
  "old_values" JSONB,
  "new_values" JSONB,
  "ipaddr" inet,
  "operation_time" timestamp(6) DEFAULT CURRENT_TIMESTAMP,
  "username" varchar(255) COLLATE "pg_catalog"."default"
)
;

-- ----------------------------
-- Primary Key structure for table operation_log
-- ----------------------------
ALTER TABLE "tb_sys_operation_log" ADD CONSTRAINT "tb_sys_operation_log_pkey" PRIMARY KEY ("id");
  1. 创建触发器函数:接下来,我们需要创建一个触发器函数,该函数将在数据库操作时被调用,并将操作的相关信息插入到日志表中。以下是一个示例的触发器函数:
CREATE OR REPLACE FUNCTION "sys_log_operation"()
  RETURNS "pg_catalog"."trigger" AS $BODY$
DECLARE
  full_sql_statement TEXT;
  stat_queryid numeric;
  operation_type TEXT;
  old_column_data JSONB;
  new_column_data JSONB;
BEGIN
    -- 获取触发器操作类型
    IF (TG_OP = 'INSERT') THEN
        operation_type := 'INSERT';
        SELECT to_jsonb(NEW) INTO new_column_data;
    ELSIF (TG_OP = 'UPDATE') THEN
        operation_type := 'UPDATE';
        SELECT to_jsonb(OLD) INTO old_column_data;
        SELECT to_jsonb(NEW) INTO new_column_data;
    ELSIF (TG_OP = 'DELETE') THEN
        operation_type := 'DELETE';
        SELECT to_jsonb(OLD) INTO old_column_data;
    END IF;
		
		SELECT query INTO full_sql_statement
    FROM pg_stat_activity
    WHERE pg_stat_activity.pid = pg_backend_pid();

    -- 插入操作信息到日志表
    INSERT INTO tb_sys_operation_log (username,operation_tablename,operation_time, operation_type, sql_statement,ipaddr,old_values,new_values,operation_pid)
    VALUES (current_user,TG_TABLE_NAME,now(), operation_type, full_sql_statement,inet_client_addr(),old_column_data,new_column_data,pg_backend_pid());
    RETURN NEW;
END;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100
  1. 创建触发器:最后,我们需要创建一个触发器,将触发器函数与要监视的数据库表关联起来。以下是一个示例的触发器创建语句:
CREATE TRIGGER log_operation_trigger
AFTER INSERT OR UPDATE OR DELETE ON your_table
FOR EACH ROW
EXECUTE FUNCTION sys_log_operation();

在上面的代码中,将"your_table"替换为实际要监视的数据库表的名称。这个触发器将在每次插入、更新或删除记录时调用触发器函数,并将相关信息插入到日志表中。

过程中其他问题

1.1. pg_stat_activity表记录sql的长度截取问题

		SELECT query INTO full_sql_statement
    FROM pg_stat_activity
    WHERE pg_stat_activity.pid = pg_backend_pid();

其中pg_stat_activity表中sql的记录信息,会发生截取长度的问题,其长度取决于postgresql.conf配置文件中的track_activity_query_size,其默认值为1024,将配置文件中的该值打开注释,设置值并重启数据库。

结论

通过使用 PostgreSQL 触发器记录数据库操作的 SQL 语句,我们可以方便地追踪和监控应用程序对数据库的操作。这个解决方案提供了一种简单而有效的方法来记录和审计 SQL 语句,有助于调试和排查问题。


http://lihuaxi.xjx100.cn/news/1280150.html

相关文章

【Java入门】方法及方法重载

方法及方法重载 方法的定义、调用及其注意事项 方法:是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集 1、定义格式: 修饰符 返回值类型 方法名(参数){ 方法体; 返回值; } 参数的种类:形式参数和实际参数 形参:方法声明的不具有数…

chatgpt赋能python:Python要点:从入门到精通

Python要点:从入门到精通 Python是一门高级编程语言,是一种解释型、面向对象、动态数据类型的语言。它的设计思想是“代码易读易写”,在数据科学、人工智能、自动化测试、Web开发等领域广泛应用。本文将从入门到精通的角度来介绍Python的要点…

h2database BTree 设计实现与查询优化思考 | 京东云技术团队

h2database 是使用Java 编写的开源数据库,兼容ANSI-SQL89。既实现了常规基于 BTree 的存储引擎,又支持日志结构存储引擎。功能非常丰富(死锁检测机制、事务特性、MVCC、运维工具等),数据库学习非常好的案例。 本文理论…

机器学习4:基本术语

机器学习涉及很多专业术语,为了避免混淆概念,我们在学习中,首先必须统一语言:即充分理解专业术语,并采用专业术语来描述机器学习相关的内容。本节将介绍几种基本的机器学习术语。 目录 1.标签 2.特征 3.示例 4.模…

树莓派4B移植5G模块驱动(RG200U-CN)

1、查看Linux内核版本 uname -r2、根据内核版本在Github上下载Linux内核源码(最好再Github上确定一下有没有这个分支) git clone --depth1 https://github.com/raspberrypi/linux --branch rpi-5.15.y3、下载依赖库 sudo apt-get updatesudo apt-get …

Linux磁盘分区和文件系统的关系

一、Linux磁盘相关命令及作用: 1. df命令:用于显示文件系统的磁盘空间使用情况。 2. du命令:用于查看文件或目录的磁盘使用情况。 3. fdisk命令:用于磁盘分区表的创建和管理。 4. mkfs命令:用于创建文件系统。 5. moun…

【css】实现单独一区域滚动,不影响整体滚动

来源:css实现单独一区域滚动,不影响整体滚动,两种方法 方法 第一种:就该区域高度固定,然后overflow-auto 第二种:使用属性overscroll-behavior: contain; .overfolw{position: absolute;width: 100%;ov…

C++ Vector操作

文章目录 1 初始化:2 遍历vector3删除vector指定元素 1 初始化: 方法1: vector list1; //默认初始化,vector 为空, size 为0。容器中没有元素,而且 capacity 也返回 0,意味着还没有分配内存空…