用触发器生成数据库表的数据操作日志

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介:

作为一名数据库管理员,你尽力以各部门熟知的不同格式,向各部门提供它们所需要的数据。你通常将MS Excel格式的数据递交到会计部门,或将数据以HTML报表的形式呈现给普通用户。你们的系统安全管理员们则习惯于用文本阅读器或者事件查看器来查看日志。本文将介绍如何使用触发器,把DML(数据操作语言)对数据库中的特定数据表的改动记录下来。注:下列例子为Insert型触发器,不过改成Delete/Update型的触发器也很容易。

操作步骤首先让我们在Northwind数据库内创建一个简单表。

create table tablefortrigger

track int identity(1,1) primary key, 
Lastname varchar(25), 
Firstname varchar(25) 
)

创建好这个数据表后,添加一个标准message到master数据库的sysmessages数据表中。注意,我所添加的是一个参变量,用以接受一个字符值,它将被输出显示给管理员们。通过设置@_with_log参数为true,我们包管相关结果被发送到事件日志。

sp_addmessage 50005, 10, '%s', @with_log = true

现在我们创建这条用有意义的信息填充的消息。下面的信息将填充这条消息,并且记录到文件中:

·操作的类型(插入)。

·受到影响的数据表。

·改动的日期与时间。

被该语句插入的全部字段。 下面的这个触发器用预定义值(1~3个字符)创建一个字符串,该预定义值位于inserted数据表中。(这个inserted数据表驻留在内存中,它容纳被插入到触发器所在数据表的记录行)。触发器连接这些值并放到一个@msg变量。然后这个变量被传送到raiserror函数,该函数将它写到事件日志中。

Create trigger TestTrigger on 
tablefortrigger 
for insert 
as
--声明储存消息的变量 
Declare @Msg varchar(8000) 
--将"操作/表名/日期时间/插入字段"赋与消息
set @Msg = 'Inserted | tablefortrigger | ' + convert(varchar(20), getdate()) + ' | ' 
+(select convert(varchar(5), track) 
+ ', ' + lastname + ', ' + firstname 
from inserted) 
--产生错误发送给事件查看器。
raiserror( 50005, 10, 1, @Msg)

运行以下语句对触发器进行测试,然后查看事件日志:

Insert into tablefortrigger(lastname, firstname) 
Values('Doe', 'John')

如果你打开事件日志,你应该看到以下消息:


(图1)

既然我们已经有办法写入事件日志了,那么让我们修改一下触发器,将数据写到一个文本文件中。这次改动还须添加另一个变量@CmdString,以及使用扩展储存过程xp_cmdshell。

因为我们要写入文件系统,安全权限开始有影响了。所以,执行插入操作的用户必须具备该文本文件的读写权限。因此,设计一个C/S结构的应用程序供多用户运行,或许不是一个可行的解决方案。更合理的方案是,设计一个三层应用程序,由你的中间层组件对单用户数据库进行调用。在后一个方案中,对那个文本文件的权限管理其实比管理一个用户还容易。

Alter trigger TestTrigger on 
tablefortrigger 
for insert 
as 
Declare @Msg varchar(1000) 
--储存将由xp_cmdshell执行的命令
Declare @CmdString varchar (2000) 
set @_msg = ' insert | tablefortrigger | ' + convert ( varchar ( 20 ) , getdate ( ) ) + ' | ' + ( select convert ( varchar ( 5 ) , track ) + ' , ' + lastname + ' , ' + firstname from insert ) - 
[99%]set @Msg = 'Inserted | tablefortrigger | ' + convert(varchar(20), getdate()) + ' | ' +(select convert(varchar(5), track) + ', ' + lastname + ', ' + firstname from inserted) 
--产生错误发送给事件查看器。
raiserror( 50005, 10, 1, @Msg) 
set @CmdString = 'echo ' + @Msg + ' >> C:\logtest.log' 
--写到文本文件
exec master.dbo.xp_cmdshell @CmdString

让我们对它进行测试,先运行前面的插入语句,然后打开C:\logtest.log文件查看结果:

Insert into tablefortrigger(lastname, firstname) Values('Doe', 'John')

问题解决了,对不对?哦,还没完全解决。发生多次重复插入的事件是什么原因?在这个例子中,你必须分别地处理每条记录。为了达到这个目的,我们必须用一个会带来麻烦的游标来访问"隐蔽面"。在执行以前,我必须预先给予警告。你应当了解的是,当这个应用程序进行大规模地记录插入、更新或删除时要当心,因为它可能会耗费大量的内存。

像你从下面看到的一样,这次我们在前面那个例子的基础上稍加调整,引入了一个游标,对该插入表的全部记录进行循环读取。每条记录分别插入一条线条,将各个事件区分开来。 

ALTER trigger TestTrigger on tablefortrigger 
for insert 
as 
Declare @Msg varchar(1000) 
Declare @CmdString varchar (1000) 
Declare GetinsertedCursor cursor for 
Select 'Inserted | tablefortrigger | ' + convert(varchar(20), getdate()) + ' | ' 
+ convert(varchar(5), track) 
+ ', ' + lastname + ', ' + firstname 
from inserted 

open GetinsertedCursor 
Fetch Next from GetinsertedCursor 
into @Msg 

while @@fetch_status = 0 
Begin 
raiserror( 50005, 10, 1, @Msg) 
Fetch Next from GetinsertedCursor 
into @Msg 
set @CmdString = 'echo ' + @Msg + ' >> C:\logtest.log' 
exec master.dbo.xp_cmdshell @CmdString 
End 
close Getinsertedcursor 
deallocate GetInsertedCursor

现在让我们执行重复多次插入测试:

Insert into tablefortrigger(lastname, firstname) 
Select lastname, firstname from employees

结论

在继续完成之前,有些人认为必须考虑性能与安全问题。你将看到写入文本文件的开销,而对于一个每分钟处理5000项事务的数据库来说,这样大的开销也许不可接受。由于xp_cmdshell是在SQL外操作的,写入到文件的错误不会回滚事务。倘若入侵者使用一个隐蔽的途径来改变你的数据,这个事件不会被登记到那个文本文件中。不过事件日志将记录该次DML改动。作为一次最好的实践,各事件的编号应该被用于对照日志文件的各行记录,以便发现所有的差异。

有很多种方法可以达到本文目标,上述脚本也可以有许多的变化。我希望你能接受这个脚本,然后作出改进并提出建议,使它更有效率。

专注于企业信息化,最近对股票数据分析较为感兴趣,可免费分享股票个股主力资金实时变化趋势分析工具,股票交流QQ群:457394862

本文转自沧海-重庆博客园博客,原文链接:http://www.cnblogs.com/omygod/archive/2006/11/24/570635.html,如需转载请自行联系原作者
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
目录
相关文章
|
1月前
|
存储 人工智能 Cloud Native
云栖重磅|从数据到智能:Data+AI驱动的云原生数据库
在9月20日2024云栖大会上,阿里云智能集团副总裁,数据库产品事业部负责人,ACM、CCF、IEEE会士(Fellow)李飞飞发表《从数据到智能:Data+AI驱动的云原生数据库》主题演讲。他表示,数据是生成式AI的核心资产,大模型时代的数据管理系统需具备多模处理和实时分析能力。阿里云瑶池将数据+AI全面融合,构建一站式多模数据管理平台,以数据驱动决策与创新,为用户提供像“搭积木”一样易用、好用、高可用的使用体验。
云栖重磅|从数据到智能:Data+AI驱动的云原生数据库
|
22天前
|
存储 监控 数据处理
flink 向doris 数据库写入数据时出现背压如何排查?
本文介绍了如何确定和解决Flink任务向Doris数据库写入数据时遇到的背压问题。首先通过Flink Web UI和性能指标监控识别背压,然后从Doris数据库性能、网络连接稳定性、Flink任务数据处理逻辑及资源配置等方面排查原因,并通过分析相关日志进一步定位问题。
150 61
|
1月前
|
存储 Oracle 关系型数据库
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
本文介绍了MySQL InnoDB存储引擎中的数据文件和重做日志文件。数据文件包括`.ibd`和`ibdata`文件,用于存放InnoDB数据和索引。重做日志文件(redo log)确保数据的可靠性和事务的持久性,其大小和路径可由相关参数配置。文章还提供了视频讲解和示例代码。
134 11
【赵渝强老师】MySQL InnoDB的数据文件与重做日志文件
|
20天前
|
关系型数据库 MySQL 数据库
GBase 数据库如何像MYSQL一样存放多行数据
GBase 数据库如何像MYSQL一样存放多行数据
|
1月前
|
SQL 关系型数据库 数据库
国产数据实战之docker部署MyWebSQL数据库管理工具
【10月更文挑战第23天】国产数据实战之docker部署MyWebSQL数据库管理工具
123 4
国产数据实战之docker部署MyWebSQL数据库管理工具
|
1月前
|
关系型数据库 分布式数据库 数据库
云栖大会|从数据到决策:AI时代数据库如何实现高效数据管理?
在2024云栖大会「海量数据的高效存储与管理」专场,阿里云瑶池讲师团携手AMD、FunPlus、太美医疗科技、中石化、平安科技以及小赢科技、迅雷集团的资深技术专家深入分享了阿里云在OLTP方向的最新技术进展和行业最佳实践。
|
2月前
|
人工智能 Cloud Native 容灾
云数据库“再进化”,OB Cloud如何打造云时代的数据底座?
云数据库“再进化”,OB Cloud如何打造云时代的数据底座?
|
2月前
|
SQL 存储 关系型数据库
数据储存数据库管理系统(DBMS)
【10月更文挑战第11天】
131 3
|
1月前
|
SQL Oracle 关系型数据库
【赵渝强老师】Oracle的联机重做日志文件与数据写入过程
在Oracle数据库中,联机重做日志文件记录了数据库的变化,用于实例恢复。每个数据库有多组联机重做日志,每组建议至少有两个成员。通过SQL语句可查看日志文件信息。视频讲解和示意图进一步解释了这一过程。
|
2月前
|
NoSQL 前端开发 MongoDB
前端的全栈之路Meteor篇(三):运行在浏览器端的NoSQL数据库副本-MiniMongo介绍及其前后端数据实时同步示例
MiniMongo 是 Meteor 框架中的客户端数据库组件,模拟了 MongoDB 的核心功能,允许前端开发者使用类似 MongoDB 的 API 进行数据操作。通过 Meteor 的数据同步机制,MiniMongo 与服务器端的 MongoDB 实现实时数据同步,确保数据一致性,支持发布/订阅模型和响应式数据源,适用于实时聊天、项目管理和协作工具等应用场景。