以最干净的方式记录CF-ORM/Hibernate中谁更新了什么?

以最干净的方式记录CF-ORM/Hibernate中谁更新了什么?,hibernate,orm,coldfusion,versioning,Hibernate,Orm,Coldfusion,Versioning,我的项目的一个要求是记录谁、哪些员工将什么从什么版本更新到了什么版本。UI需要显示谁在什么时间更新了实体X以及更新了什么 实现这一点最干净的方法是什么 为了便于讨论,想象一下。。。帐户有一个联系人,我需要存储更新联系人的人、时间和更新内容。有一个单独的历史记录表,用于跟踪: 桌子 柱 插入、更新、删除操作 修改行的pk 要更新的旧值 更新的新值 进行更改的人员的用户名 时间戳 用触发器更新它,你不必担心任何事情 或者研究一个叫做。一些数据库供应商,如Oracle,已将其内置到其产品中。你只要打开

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

实现这一点最干净的方法是什么


为了便于讨论,想象一下。。。帐户有一个联系人,我需要存储更新联系人的人、时间和更新内容。

有一个单独的历史记录表,用于跟踪:

桌子 柱 插入、更新、删除操作 修改行的pk 要更新的旧值 更新的新值 进行更改的人员的用户名 时间戳 用触发器更新它,你不必担心任何事情


或者研究一个叫做。一些数据库供应商,如Oracle,已将其内置到其产品中。你只要打开它就行了。也许你的表已经有了。

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

然后我使用触发器。我不同意有人说使用触发器会污染数据模型。如果规则需要跟踪对数据库的更改,那么将规则放入数据库似乎是合适的位置。正如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

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

这就给我们留下了一个问题,即知道是哪个用户进行了每次更改。只要在应用程序打开数据库连接时调用存储过程,就可以将应用程序用户标识映射到数据库会话标识

然后,触发器可以从会话id获取用户id

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

CF-ORM可以通过ormconfig来实现这一点

对于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

thx,但DB trigger不适用于我,因为它无法记录谁对数据进行了更改。trigger如何跟踪进行更改的人的用户名?它必须以某种方式获取用户名。它必须被传递进来。