【问题标题】:Cleanest way to log who updated what in CF-ORM / Hibernate?记录谁在 CF-ORM / Hibernate 中更新了什么的最干净的方法?
【发布时间】:2011-01-18 15:03:12
【问题描述】:

我的项目的一个要求是记录谁(哪个员工)更新了什么(从什么版本到什么版本)。 UI 需要显示谁在什么时间更新了实体 X 以及更新了什么。

什么是最简洁的实现方式?

出于讨论目的,想象一下……帐户有一个联系人,我需要存储谁更新了联系人、何时以及更新了什么。

【问题讨论】:

    标签: hibernate orm coldfusion versioning


    【解决方案1】:

    有一个单独的历史记录表来跟踪:

    1. 表格
    2. 操作(插入、更新、删除)
    3. 修改行的pk
    4. 旧值(用于更新)
    5. 新值(用于更新)
    6. 进行更改的人的用户名
    7. 时间戳

    使用触发器更新它,您不必担心任何事情。

    或研究一个名为"change data capture" 的主题。一些数据库供应商,如 Oracle,已将其内置到他们的产品中。你只需要打开它。也许你的已经有了。

    【讨论】:

    • 触发器如何跟踪“进行更改的人的用户名”?
    • 它必须以某种方式获取用户名。它必须被传入。
    【解决方案2】:

    我为我正在审核的每个表保留一个单独的表。表名相同,架构不同。示例:dbo.Usr = Audit.Usr。 Audit.Usr 包括 2 个新字段:一个新的主键和一个日期/时间字段。

    然后我使用触发器。我不同意有人说使用触发器会污染数据模型。如果规则需要跟踪对数据库的更改,那么将规则放入数据库似乎是合适的地方。正如 Paul Nielsen 在 SQL Server 圣经中所说:任何不在数据库级别强制执行的规则都不是规则,它们只是建议。

    这是一个我正在审核对 usr 表的更改的示例。巧合的是,我们正在跟踪更改了 Usr 表的 UsrID,因此有一个名为 Usr_UsrID 的字段。在除了 Usr 表之外的任何其他表中,名为 Usr_UsrID 的字段会更有意义。

    IF  EXISTS (SELECT * FROM sys.schemas WHERE name = N'Audit')
    DROP SCHEMA Audit
    GO
    CREATE SCHEMA Audit AUTHORIZATION dbo
    GO
    CREATE TABLE Audit.AuditType(
    AuditTypeID Int Identity(1,1) Constraint AuditTypeID Primary Key,
    AuditTypeName Varchar(128),
    AuditTypeDesc Varchar(128),
    AuditTypeSort Int default 0
    )
    GO
    INSERT INTO Audit.AuditType(AuditTypeName,AuditTypeSort,AuditTypeDesc) VALUES('Insert',1,'Insert')
    INSERT INTO Audit.AuditType(AuditTypeName,AuditTypeSort,AuditTypeDesc) VALUES('Change',2,'Old Value')
    INSERT INTO Audit.AuditType(AuditTypeName,AuditTypeSort,AuditTypeDesc) VALUES('New Value',3,'New Value')
    INSERT INTO Audit.AuditType(AuditTypeName,AuditTypeSort,AuditTypeDesc) VALUES('Delete',4,'Delete')
    GO
    IF  EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'dbo.AuditInsert_Usr'))
    DROP TRIGGER dbo.AuditInsert_Usr
    GO
    CREATE Trigger AuditInsert_Usr ON dbo.Usr AFTER Insert
    NOT FOR REPLICATION AS
    INSERT INTO Audit.Usr(AuditUsr_AuditTypeID,
    UsrID,UsrName,UsrPassword,Usr_UsrID)
    SELECT 1,
    UsrID,UsrName,UsrPassword,Usr_UsrID
    FROM Inserted
    GO
    
    IF  EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'dbo.AuditUpdate_Usr'))
    DROP TRIGGER dbo.AuditUpdate_Usr
    GO
    CREATE Trigger AuditUpdate_Usr ON dbo.Usr AFTER Update
    NOT FOR REPLICATION AS
    INSERT INTO Audit.Usr(AuditUsr_AuditTypeID,
    UsrID,UsrName,UsrPassword,Usr_UsrID)
    SELECT 2,
    Deleted.UsrID,Deleted.UsrName,Deleted.UsrPassword,Deleted.Usr_UsrID
    FROM Inserted
    JOIN Deleted
    ON Inserted.UsrID = Deleted.UsrID
    WHERE Inserted.UsrName  <> Deleted.UsrName
    OR Inserted.UsrPassword <> Deleted.UsrPassword
    OR Inserted.Usr_UsrID   <> Deleted.Usr_UsrID;
    INSERT INTO Audit.Usr(AuditUsr_AuditTypeID,
    UsrID,UsrName,UsrPassword,Usr_UsrID)
    SELECT 3,
    Inserted.UsrID,Inserted.UsrName,Inserted.UsrPassword,Inserted.Usr_UsrID
    FROM Inserted
    JOIN Deleted
    ON Inserted.UsrID = Deleted.UsrID
    WHERE Inserted.UsrName  <> Deleted.UsrName
    OR Inserted.UsrPassword <> Deleted.UsrPassword
    OR Inserted.Usr_UsrID   <> Deleted.Usr_UsrID;
    GO
    
    IF  EXISTS (SELECT * FROM sys.triggers WHERE object_id = OBJECT_ID(N'dbo.AuditDelete_Usr'))
    DROP TRIGGER dbo.AuditDelete_Usr
    GO
    CREATE Trigger AuditDelete_Usr ON dbo.Usr AFTER Delete
    NOT FOR REPLICATION AS
    INSERT INTO Audit.Usr(AuditUsr_AuditTypeID,
    UsrID,UsrName,UsrPassword,Usr_UsrID)
    SELECT 4,
    UsrID,UsrName,UsrPassword,Usr_UsrID
    FROM Deleted
    GO
    

    【讨论】:

    • 谢谢,但数据库触发器对我不起作用,因为它无法记录谁对数据进行了更改。
    【解决方案3】:

    我们可以使用以下描述的方法通过触发器跟踪更改 @cf_PhillipSenn 和 @duffymo 在他们的回答中。

    这给我们留下了一个问题,即要知道每个更改是由哪个用户进行的。每当应用程序打开数据库连接时,我们只需要调用一个存储过程来将应用程序用户 ID 映射到数据库会话 ID。

    然后触发器可以从会话 ID 中获取用户 ID。

    在 Hibernate 中,我们可以通过提供我们自己的org.hibernate.connection.ConnectionProvider 在打开连接后调用该过程来确保为每个新连接调用此过程。这个类很可能是DatasourceConnectionProvider.javaDriverManagerConnectionProvider 的子类。

    CF-ORM 或许可以通过 ormconfig property 做到这一点。

    对于 SQL Server,会话表和存储过程的用户如下所示:

    CREATE TABLE UserToSPID (
        SPID    int PRIMARY KEY,
        UserId  int
    )
    
    CREATE PROCEDURE dbo.[UserToSPID_Register]
        @UserId         int
    AS
        delete from UserToSPID where spid=@@spid;
        insert into UserToSPID (SPID,userid) values (@@spid,@userid);
    GO
    

    【讨论】:

      猜你喜欢
      • 2018-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-20
      • 2011-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多