在数据库管理过程中,明确谁在什么时间修改了哪些SQL数据,是排查数据异常、保障数据安全的必要工作。常见的实现方式有两种,分别是利用数据库自带的系统审计日志,以及通过自定义触发器实现监控。

方案一:利用系统审计日志实现监控
主流的关系型数据库大多自带系统审计功能,开启后可以自动记录所有数据操作的相关信息,无需额外编写业务逻辑。不同数据库的审计配置方式略有差异,下面以MySQL和SQL Server为例说明。
MySQL开启审计日志
MySQL的通用日志和二进制日志都可以用于操作记录,若需要更细粒度的审计,可开启审计插件。首先查看当前日志配置状态:
-- 查看通用日志是否开启 SHOW VARIABLES LIKE 'general_log'; -- 查看二进制日志是否开启 SHOW VARIABLES LIKE 'log_bin';
开启通用日志的命令如下,开启后会记录所有客户端连接和执行的SQL语句:
-- 开启通用日志 SET GLOBAL general_log = 'ON'; -- 设置通用日志存储路径 SET GLOBAL general_log_file = '/var/lib/mysql/general.log';
通用日志会记录操作时间、执行用户、具体操作内容,但是日志量较大,适合短期排查使用。如果需要长期审计,建议使用二进制日志配合解析工具,二进制日志主要记录数据变更操作,体积更小。
SQL Server开启审计
SQL Server可以通过SQL Server Audit功能实现操作监控,首先创建审计对象并绑定到服务器:
-- 创建审计对象,指定日志存储路径 CREATE SERVER AUDIT DataChangeAudit TO FILE (FILEPATH = 'C:AuditLogs'); -- 开启审计 ALTER SERVER AUDIT DataChangeAudit WITH (STATE = ON); -- 创建审计规范,监控所有数据修改操作 CREATE DATABASE AUDIT SPECIFICATION DataChangeSpec FOR SERVER AUDIT DataChangeAudit ADD (UPDATE, INSERT, DELETE ON DATABASE::TestDB BY PUBLIC); -- 开启审计规范 ALTER DATABASE AUDIT SPECIFICATION DataChangeSpec WITH (STATE = ON);
开启后,所有对TestDB数据库的增删改操作都会被记录到指定路径的审计文件中,包含操作时间、登录用户、操作语句等信息。
方案二:自定义触发器实现监控
如果只需要监控特定表的数据修改操作,自定义触发器是更灵活的选择。触发器可以在数据发生变更时自动执行,将变更信息写入自定义的监控表。下面以MySQL为例实现用户表的修改监控。
第一步:创建监控记录表
首先创建一张表,用于存储数据变更的相关信息:
CREATE TABLE data_change_log (
id INT PRIMARY KEY AUTO_INCREMENT,
table_name VARCHAR(50) NOT NULL COMMENT '被修改的表名',
operation_type VARCHAR(10) NOT NULL COMMENT '操作类型:INSERT/UPDATE/DELETE',
operator VARCHAR(50) NOT NULL COMMENT '操作人',
operation_time DATETIME NOT NULL COMMENT '操作时间',
old_data TEXT COMMENT '修改前的数据,删除操作时记录原数据',
new_data TEXT COMMENT '修改后的数据,插入操作时记录新数据'
);
第二步:创建对应触发器
针对用户表user_info的增删改操作分别创建触发器,在操作时自动写入监控记录:
-- 插入操作触发器
DELIMITER //
CREATE TRIGGER user_insert_trigger
AFTER INSERT ON user_info
FOR EACH ROW
BEGIN
INSERT INTO data_change_log (table_name, operation_type, operator, operation_time, new_data)
VALUES ('user_info', 'INSERT', USER(), NOW(), CONCAT('id:', NEW.id, ',name:', NEW.name, ',age:', NEW.age));
END //
DELIMITER ;
-- 更新操作触发器
DELIMITER //
CREATE TRIGGER user_update_trigger
AFTER UPDATE ON user_info
FOR EACH ROW
BEGIN
INSERT INTO data_change_log (table_name, operation_type, operator, operation_time, old_data, new_data)
VALUES ('user_info', 'UPDATE', USER(), NOW(),
CONCAT('id:', OLD.id, ',name:', OLD.name, ',age:', OLD.age),
CONCAT('id:', NEW.id, ',name:', NEW.name, ',age:', NEW.age));
END //
DELIMITER ;
-- 删除操作触发器
DELIMITER //
CREATE TRIGGER user_delete_trigger
AFTER DELETE ON user_info
FOR EACH ROW
BEGIN
INSERT INTO data_change_log (table_name, operation_type, operator, operation_time, old_data)
VALUES ('user_info', 'DELETE', USER(), NOW(), CONCAT('id:', OLD.id, ',name:', OLD.name, ',age:', OLD.age));
END //
DELIMITER ;
创建完成后,所有对user_info表的增删改操作都会自动同步到data_change_log表中,后续查询该表即可获取所有变更记录。
两种方案对比
两种方案各有优劣,可根据实际需求选择:
| 对比维度 | 系统审计日志 | 自定义触发器 |
|---|---|---|
| 配置复杂度 | 低,仅需开启数据库自带功能 | 中,需要创建监控表和触发器 |
| 监控范围 | 可覆盖全库或指定库的所有操作 | 仅能监控绑定触发器的表 |
| 灵活性 | 低,日志格式和存储路径固定 | 高,可自定义记录内容和存储逻辑 |
| 性能影响 | 较高,全量记录会产生大量日志 | 较低,仅针对指定表操作生效 |
注意事项
- 系统审计日志开启后需要定期清理,避免日志文件占用过多磁盘空间。
- 自定义触发器的逻辑要尽量简单,避免复杂的业务逻辑影响数据操作的性能。
- 监控表需要设置合理的权限,避免监控记录被恶意篡改,保障追溯的有效性。
- 如果需要监控分布式数据库的操作,建议优先选择数据库自带的审计功能,适配性更好。