我的項目的一個要求是記錄誰(哪個員工)更新了什麼(從什麼版本到哪個版本)。用戶界面需要在什麼時間顯示誰更新了實體X以及哪些內容已更新。最簡潔的方法來記錄誰更新了CF-ORM/Hibernate中的內容?
什麼是最簡潔的方式來實現呢?
出於討論目的,想象一下...帳戶有聯繫人,我需要存儲誰更新了聯繫人,何時更新了內容。
我的項目的一個要求是記錄誰(哪個員工)更新了什麼(從什麼版本到哪個版本)。用戶界面需要在什麼時間顯示誰更新了實體X以及哪些內容已更新。最簡潔的方法來記錄誰更新了CF-ORM/Hibernate中的內容?
什麼是最簡潔的方式來實現呢?
出於討論目的,想象一下...帳戶有聯繫人,我需要存儲誰更新了聯繫人,何時更新了內容。
我爲每個正在審覈的表保留一張單獨的表格。表名是相同的,架構是不同的。例如: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
有跟蹤一個單獨的歷史表:
與觸發更新它,你不必擔心什麼。
或研究題爲"change data capture"的主題。一些數據庫供應商,如Oracle,已將其內置到他們的產品中。你只需打開它。也許你已經擁有了它。
我們可以跟蹤通過使用他們的答案被 @cf_PhillipSenn描述的方法和@duffymo觸發器的變化。
這讓我們知道哪些用戶進行了每次更改。只要應用程序打開數據庫連接以將應用程序用戶標識映射到數據庫會話標識,我們就需要調用存儲過程。
觸發器可以從會話ID獲取用戶標識。
在Hibernate中,我們可以通過提供我們自己的org.hibernate.connection.ConnectionProvider
來確保每個新連接都調用這個過程,它在打開連接後調用proc。這個類最有可能是DatasourceConnectionProvider.java
或DriverManagerConnectionProvider
的子類。
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 [email protected]@spid;
insert into UserToSPID (SPID,userid) values (@@spid,@userid);
GO
thx,但數據庫觸發器不適用於我,因爲它無法記錄誰對數據進行了更改。 – Henry 2010-02-19 19:10:29