Nic*_*ver 8 oracle audit triggers
首先,我们目前有所需的行为,但是当需要对数据库进行任何更改时,维护它并非易事.我正在寻找更简单,更有效或更容易维护的东西(任何能够做到这三者的东西都是最受欢迎的).当我们执行更新时,会创建一个历史行,它是当前行的副本,然后更新当前行的值.结果是我们有一个关于行在更新之前的历史记录.
推理:我们必须遵守一系列联邦规则,然后通过这条路线获得所有内容的完整审计历史记录,以及我们可以随时查看数据库并查看事物的外观(未来要求) . 出于类似的原因,我无法改变历史记录的记录方式 ......任何解决方案都必须产生与当前触发器创建的数据相同的数据.
以下是ContactTable 的当前触发器的样子:(
为简洁起见,剥离无用字段,字段数无关紧要)
更新前(每行):
DECLARE
indexnb number;
BEGIN
:new.date_modified := '31-DEC-9999';
indexnb := STATE_PKG.newCONTACTRows.count + 1;
:new.date_start := sysdate;
:new.version := :old.version + 1;
state_pkg.newCONTACTRows(indexnb).ID := :old.ID;
state_pkg.newCONTACTRows(indexnb).PREFIX := :old.PREFIX;
state_pkg.newCONTACTRows(indexnb).FIRST_NAME := :old.FIRST_NAME;
state_pkg.newCONTACTRows(indexnb).MIDDLE_NAME := :old.MIDDLE_NAME;
state_pkg.newCONTACTRows(indexnb).LAST_NAME := :old.LAST_NAME;
--Audit columns after this
state_pkg.newCONTACTRows(indexnb).OWNER := :old.OWNER;
state_pkg.newCONTACTRows(indexnb).LAST_USER := :old.LAST_USER;
state_pkg.newCONTACTRows(indexnb).DATE_CREATED := :old.DATE_CREATED;
state_pkg.newCONTACTRows(indexnb).DATE_MODIFIED := sysdate;
state_pkg.newCONTACTRows(indexnb).VERSION := :old.VERSION;
state_pkg.newCONTACTRows(indexnb).ENTITY_ID := :old.id;
state_pkg.newCONTACTRows(indexnb).RECORD_STATUS := :old.RECORD_STATUS;
state_pkg.newCONTACTRows(indexnb).DATE_START := :old.DATE_START;
END;
Run Code Online (Sandbox Code Playgroud)
更新前(所有行一次):
BEGIN
state_pkg.newCONTACTRows := state_pkg.eCONTACTRows;
END;
Run Code Online (Sandbox Code Playgroud)
更新后(所有行一次):
DECLARE
BEGIN
for i in 1 .. STATE_PKG.newCONTACTRows.COUNT loop
INSERT INTO "CONTACT" (
ID,
PREFIX,
FIRST_NAME,
MIDDLE_NAME,
LAST_NAME,
OWNER,
LAST_USER,
DATE_CREATED,
DATE_MODIFIED,
VERSION,
ENTITY_ID,
RECORD_STATUS,
DATE_START)
VALUES (
CONTACT_SEQ.NEXTVAL,
state_pkg.newCONTACTRows(i).PREFIX,
state_pkg.newCONTACTRows(i).FIRST_NAME,
state_pkg.newCONTACTRows(i).MIDDLE_NAME,
state_pkg.newCONTACTRows(i).LAST_NAME,
state_pkg.newCONTACTRows(i).OWNER,
state_pkg.newCONTACTRows(i).LAST_USER,
state_pkg.newCONTACTRows(i).DATE_CREATED,
state_pkg.newCONTACTRows(i).DATE_MODIFIED,
state_pkg.newCONTACTRows(i).VERSION,
state_pkg.newCONTACTRows(i).ENTITY_ID,
state_pkg.newCONTACTRows(i).RECORD_STATUS,
state_pkg.newCONTACTRows(i).DATE_START
);
end loop;
END;
Run Code Online (Sandbox Code Playgroud)
定义为的包(修剪完整版只是每个表的副本):
PACKAGE STATE_PKG IS
TYPE CONTACTArray IS TABLE OF CONTACT%ROWTYPE INDEX BY BINARY_INTEGER;
newCONTACTRows CONTACTArray;
eCONTACTRows CONTACTArray;
END;
Run Code Online (Sandbox Code Playgroud)
这是一个结果历史样本:
ID First Last Ver Entity_ID Date_Start Date_Modified
1196 John Smith 5 0 12/11/2009 10:20:11 PM 12/31/9999 12:00:00 AM
1201 John Smith 0 1196 12/11/2009 09:35:20 PM 12/11/2009 10:16:49 PM
1203 John Smith 1 1196 12/11/2009 10:16:49 PM 12/11/2009 10:17:07 PM
1205 John Smith 2 1196 12/11/2009 10:17:07 PM 12/11/2009 10:17:19 PM
1207 John Smith 3 1196 12/11/2009 10:17:19 PM 12/11/2009 10:20:00 PM
1209 John Smith 4 1196 12/11/2009 10:20:00 PM 12/11/2009 10:20:11 PM
Run Code Online (Sandbox Code Playgroud)
每个历史记录都有一个Entity_ID,它是当前行的ID,新记录上的Date_Start与最后一个历史行的Date_Modified匹配.这允许我们做像这样的查询Where Entity_ID = :id Or ID = :id And :myDate < Date_Modified And :myDate >= Date_Start.历史可以通过Entity_ID = :current_id.
是否有更好的方法,希望更易于维护/灵活这样做? 这个概念很简单,在更新行时,通过带旧值的插入将其复制到同一个表中,然后更新当前行......但实际上这样做,我还没有找到一种更简单的方法.我希望甲骨文中有一个更狡猾/更聪明的人有更好的方法.速度并不重要,我们99%读取1%像大多数Web应用程序一样写入,并且所有批量操作都是插入,而不是不会创建任何历史记录的更新.
如果有人有任何想法来简化维护,我会非常感激,谢谢!
好吧,这是重写。当我第一次回复时,我错过的是应用程序将其历史记录存储在主表中。现在我明白为什么 @NickCraver 对代码如此抱歉。
首先要做的就是追捕这种设计的肇事者,并确保他们不再这样做。像这样存储历史记录无法扩展,使正常(非历史)查询变得更加复杂,并破坏关系完整性。显然,有些情况下这些都不重要,也许您的网站就是其中之一,但总的来说,这是一个非常糟糕的实现。
做到这一点的最佳方法是Oracle 11g Total Recall。这是一个优雅的解决方案,具有完全隐形且高效的实施方式,而且(按照 Oracle 的其他收费附加服务的标准)价格相当合理。
但是,如果《全面回忆》是不可能的,并且您确实必须这样做,则不允许更新。对现有 CONTACT 记录的更改应该是插入。为了使这项工作有效,您可能需要使用 INSTEAD OF 触发器构建一个视图。它仍然令人讨厌,但不像现在那么令人讨厌。
从 Oracle 11.2.0.4 开始,Total Recall 已更名为 Flashback Archive,并作为企业许可证的一部分包含在内(尽管除非我们购买高级压缩选项,否则会删除压缩日志表)。
Oracle 的这种慷慨应该使 FDA 成为存储历史记录的正常方式:它高效、高性能,它是 Oracle 内置的标准语法,支持历史查询。唉,我预计多年来仍会看到半生不熟的实现,其中包括触发器混乱、主键损坏和糟糕的性能。因为日志记录似乎是开发人员喜欢的干扰之一,尽管事实上它是低级管道,与 99.99% 的业务运营基本上无关。