代码之家  ›  专栏  ›  技术社区  ›  Andrej Kaurin

在数据库中保存数据更改的历史记录

  •  11
  • Andrej Kaurin  · 技术社区  · 16 年前

    数据库中某行数据的每次更改都应将前一行数据保存在某种历史记录中,以便用户可以回滚到前一行数据状态。这种方法有什么好的实践吗?尝试使用DataContract,对数据对象进行序列化和反序列化,但对复杂对象的处理会稍微混乱一些。

    更清楚地说:

    1. 我正在使用nhibernate进行数据访问,并希望避免依赖数据库(用于使用SQL Server 2005进行测试)

    2. 我的目的是提供数据历史记录,以便每次用户可以回滚到某些以前的版本。

    使用示例如下:

    • 我有一篇新闻文章
    • 有人修改了那篇文章
    • 总编辑看到这条新闻有一些错别字
    • 它决定回滚到以前的有效版本(直到更正最新版本)

    希望我给了你有效的信息。

    7 回复  |  直到 10 年前
        1
  •  14
  •   Raj More    16 年前

    当主表更改时存储更改的表称为审计表。您可以通过多种方式执行此操作:

    • 在使用触发器的数据库中: 我建议使用这种方法,因为如果没有记录,数据就无法更改。执行此操作时,必须考虑三种更改:添加、删除、更新。因此,您需要能够处理这三个问题的触发器功能。

    还请记住,一个事务可以同时修改多个记录,因此您应该使用完整的已修改记录集,而不仅仅是最后一个记录(大多数人都很晚才意识到这一点)。

    在触发器执行完成之前,控件不会返回到调用程序。所以你应该尽可能的轻和快地保存代码。

    • 在中间层使用代码: 这种方法将允许您将更改保存到另一个数据库,并可能减轻数据库的负载。但是,运行update语句的SQL程序员将完全绕过中间层,您将没有审计跟踪。

    审计表的结构

    您将拥有以下列:
    Autonumber PK, TimeStamp, ActionType + All columns from your original table
    在过去,我是通过以下方式做到这一点的:

    表结构:
    Autonumber PK, TimeStamp, ActionType, TableName, OriginalTableStructureColumns

    这个结构意味着您将为每个保存的数据表创建一个审计表。数据的保存和重建相当容易。我建议采用这种方法。 名称-值对:
    Autonumber PK, TimeStamp, ActionType, TableName, PKColumns, ColumnName, OldValue, NewValue

    这个结构允许您保存任何表,但是您必须为触发器中的每一列创建名称-值对。这是非常通用的,但是很贵。您还需要编写一些视图,通过取消数据透视来重新创建实际行。这会变得很乏味,而且通常不会采用这种方法。

        2
  •  5
  •   Robin Minto    16 年前

    微软在SQL Server 2008中引入了新的审计功能。这里有一篇文章描述了一些功能和设计目标,这些功能和设计目标可能对您选择的任何方法都有帮助。

    MSDN - Auditing in SQL Server 2008

        3
  •  5
  •   Agent_9191    16 年前

    你可以使用触发器。 这里是 one 例子。

     AutoAudit is a SQL Server (2005, 2008)
     Code-Gen utility that creates Audit
     Trail Triggers with:
    
         * Created, Modified, and RowVerwsion (incrementing INT) columns to table
         * view to reconstruct deleted rows
         * UDF to reconstruct Row History
         * Schema Audit Trigger to track schema changes
         * Re-code-gens triggers when Alter Table changes the table
    

    http://autoaudit.codeplex.com/

        4
  •  2
  •   Alexander Malfait    16 年前

    保存序列化的数据最终总是会变得混乱,您应该远离它。最好的做法是创建一个与主表具有相同列的并行“版本”表。

    例如,如果有一个名为“book”的表,列为“id”、“name”、“author”,则可以添加一个名为“book\u version”的表,列为“id”、“name”、“author”、“version\date”、“version\u user”

    每次在“book”表中插入或更新记录时,应用程序也将插入“book\u version”。

    根据您的数据库系统和您从应用程序访问数据库的方式,您可能能够完全自动化这一点(cfr条令中的可版本化插件)

        5
  •  1
  •   Craig Stuntz    16 年前

    一种方法是使用一个本地支持这个的数据库,比如 HBase . 我通常不会建议“更改您的数据库服务器以获得这一功能”,但是由于您没有在问题中指定数据库服务器,我假定您的意思是这是开放式的,并且服务器中的本地支持是这一功能的最佳实现之一。

        6
  •  0
  •   me_here    16 年前

    您使用的是什么数据库系统?如果您使用的是与ACID(原子性、一致性、隔离性、持久性)兼容的数据库,那么您就不能使用内置的回滚功能返回到以前的事务吗?

        7
  •  0
  •   Andrej Kaurin    14 年前

    我用NHibernate很好地解决了这个问题。

    对于那些感兴趣的人,请阅读: http://nhforge.org/blogs/nhibernate/archive/2010/07/05/nhibernate-auditing-v3-poor-man-s-envers.aspx