zl程序教程

您现在的位置是:首页 >  大数据

当前栏目

一个完整的用于追踪数据改变的解决方案

数据解决方案 一个 完整 改变 用于 追踪
2023-09-27 14:27:56 时间

在之前一篇介绍CDC的文章中,我说Audit Trail(或者Audit Log)是大部分企业级应用不可以或缺的功能。本篇给你一个完整的Audit Trail解决方案,不仅可以记录每一笔业务操作的信息(比如操作时间、操作者等),并且可以追踪每一笔业务引起的说有数据的改变(如果需要)。

目录
一、数据表的设计
二、数据变化的表示
三、AuditLog基本信息的写入
四、通过SQLCDC追踪源表数据变化
五、删除操作的TransactionId如何被记录?
六、通过SQL Job转储AuditLog详细信息
七、代码生成的应用

一、数据表的设计

clip_image001在数据库中,我们通过如右图所示的具有主子关系的两个表存储AuditLog相关信息。我们将“事务”作为我们进行追踪的单位,不过这里的讲的“事务”更多地指业务处理事务的概念。每一个被追踪的事务在AuditLog表具有一条匹配的记录,该记录表示该事务的基本信息:UserName(操作者)、AuditTime(操作时间)、Activity(可以看成是对事物的命名)和Description(事务补充性的描述)。主键TransactionId唯一标识一个事务。

子表AuditLogData记录事务详细的信息,即事务所引起的数据变化。一个完整的业务逻辑往往涉及到对多个数据表、多条记录的操作。而AuditLogData每一条记录表示某个事务针对某个单一数据表所带来的数据变化,而SourceTable字段表示源表的名称。而DataChange字段以XML的形式表示数据的改变,它具有如下的格式。

二、数据变化的表示

数据操作类型无外乎添加、更新和删除,我们通过不同的XML结构表示不同操作引起的数据改变。具体来说,对于添加操作,我们需要记录下插入的记录;对于删除操作,需要记录下原来的记录;而对于数据更新,则需要同时记录下更新先后的记录。

举个例子,假设我们具有一个Users表,它具有三个基本字段:Id、Name和Birthday。下面的XML分别表示添加、删除和更新操作后我们需要记录下的数据变化。

添加:


三、AuditLog基本信息的写入

我们现在我们的目标就是如何将追踪到的基于一个事务相关的信息写入到上面我们创建的两个表中。主表AuditLog的信息是很容易被写入的,比如你可以定义像下面一样的一个AuditLogger类。


AuditLogger的Write方法进行传入了Activity和Description,而没有TransactionId、UserName和AuditTime。其中AuditTime自然是当前时间,而UserName应该是登录系统的用户。而对于TransactionId,我们应该采用上下文的方式来获取,具体原因会在下面谈到。如果你直接使用System.Transactions事务实现我们进行追踪的“事务”,你可以直接使用当前事务(Transaction.Current)的DistributedIdentifier或者LocalIdentifier。


 1: var transactionId = Transaction.Current.TransactionInformation.DistributedIdentifier;
 2: //Or
 3: var transactionId = Transaction.Current.TransactionInformation.LocalIdentifier;

基于AuditLog表的事务基本信息的日志好解决,那么我们如何将事务引起的事务变化记录到AuditLogData表中呢?这样的工作我们完全实现在SQL Server中。

四、通过SQLCDC追踪源表数据变化

追踪记录每笔业务操作数据改变的利器——SQLCDC》介绍了一种有效记录基于某个数据表数据变化的方式:SQLCDC,在这里我们直接利用它来记录AuditLog的详细信息。当我们为某个表(比如Users)开启了CDC特性之后,SQL Server会为之创建一个相应的CT表(Users_CT),在默认的情况下Users_CT包含与Users表的所有字段。如果你不希望CDC追踪所有的字段,你可以显式地设定具体的字段。

AuditLogData表中有一个字段TransactionId表示记录属于哪个具体的事务,为了让CDC可以记录下正确TransactionId,需要在每一个被追踪的表中添加这么一个额外的字段。这个应该不是什么问题,比如我们的每个表中都具有6个系统字段:TransactionId、VersionNo、CreatedBy、CreatedTime、LatestUpdatedBy和LatestUpdatedTime。

由于每个数据表都具有了一个TransactionId字段,那么在进行数据提交的时候,需要将当前事务的ID为之赋值,这就是为什么我推荐采用上下文的方式来获取当前TransactionId的原因。但是,还有一个问题没有解决——数据删除操作的TransactionId如何被记录下来呢?

五、删除操作的TransactionId如何被记录?

由于代表当前事务的TransactionId最终会通过Insert或者Update SQL语句写入数据表,但是对于删除操作呢?由于我们直接调用Delete语句将相应的数据操作,表示当前删除操作所在的事务是无法被写入的,最终CDC记录下来的数据是无法反映出删除的记录隶属于哪个事务。

由于最终对数据库操作都是通过SQL提交的,或者是存储过程,或者是SQL文本。为了解决这个问题,我们只需要改变我们的SQL脚本,在Delete执行之前执行Update语句写入新的TransactionId。

也就是说,对于一个删除操作,实际上是先做Update,最后做Delete。在这种情况下,CDC会为你记录下三条记录,前两条是为Update记录的,最后一条是为Delete记录的。为了区分CDC追踪的记录是正常的Update还是为了Delete而进行的Update,我们可以做一些标记。比如你可以在TransactionId的值之前添加一个前缀,表示Update操作是为Delete而作的。

六、通过SQL Job转储AuditLog详细信息

clip_image002CDC仅仅会将基于某个表的数据改变记录到基于该表的CT表中,最终我们需要将这些CT表中的数据转存到我们指定的AuditLogData表中,这个工作可以通过SQLJob来实现。你自行创建一个SQL Job实现从若干CT表到AuditLogData的数据转存,并根据你的需要(主要是实时性的需要)配制Job执行的时间或者间隔。右图揭示了AuditLog详细信息是如何一步步地被记录的。

七、代码生成的应用

在这个解决方案中,我们需要一个不可或缺的东西:代码生成器。它用于自动生成如下的SQL脚本:为某个表开启CDC特性并指定追踪字段的T-SQL脚本,和进行AuditLog详细信息转存(丛CT表到AuditLogData表)的SQL Job脚本。关于代码生成,可以参考《与VS集成的若干种代码生成解决方案

作者:蒋金楠
微信公众账号:大内老A
微博:www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。 原文链接

实时渲染对3D设计行业带来哪些改变? 3D模型实时渲染技术优势有哪些?使用点量实时渲染方案:便捷使用云端渲染、线上协同审批环节更流畅、大幅降低硬件成本
无人机如何改变数据收集和分析 无人机承包商正在见证空中机器人在如何收集、捕获、组织、处理和存储大量数据方面的发展。从本质上说,大数据已经走出了云端,进入了天空。
云端2021观察:“变化” 2021年是新世纪来,可能变化最剧烈的一年吧,我自己的体感是这样的。 作为一名在基础设施一线研发多年的码农,不自觉地问自己:这一年都发生了什么,自己做了什么,未来能做些什么?特别是未来的‘趋势’、未来的‘风口’。下面就是自己的一些‘务虚’思考。
关于拖车跟踪解决方案,您应该了解的5件事 透明的监控是企业应该在其车队中安装拖车跟踪解决方案的主要原因之一,但这并不是唯一的原因。跟踪拖车和其他商用车辆的能力减少了未经授权使用、盗窃的机会,并促进更好地利用资产。