如果有子表填充了引用的数据INITIATIVEID
列,Oracle 应该通过阻止您通过更改父项的主键来创建孤立行,从而自动使更改主键值变得困难。因此,例如,如果有一个子表具有外键约束TPM_INITIATIVES
这个子表中有一行INITIATIVEID
17,您将无法更改INITIATIVEID
中的行的TPM_INITIAITVES
当前值为 17 的表。如果任何子表中都没有引用该特定行的行TPM_INITIATIVES
表中,您可以更改该值,但据推测,如果没有关系,则更改主键值并不重要,因为根据定义,它不会导致数据完整性问题。当然,您可以使用代码将新行插入到TPM_INITIATIVES
与一个新的INITIATIVEID
,将子表中所有引用旧行的行更改为引用新行,然后修改旧行。但这不会被任何提议的解决方案所困。
如果您的应用程序已定义子表但未声明适当的外键约束,那么这将是解决问题的最佳方法。
话虽如此,Arnon 创建视图的解决方案应该可行。您可以重命名该表,创建一个与现有表同名的视图,并(可能)在该视图上定义一个 INSTEAD OF 触发器,该触发器永远不会更新该表INITIATIVEID
柱子。这不需要更改应用程序的其他部分。
您还可以在表上定义触发器
CREATE TRIGGER trigger_name
BEFORE UPDATE ON TPM_INITIATIVES
FOR EACH ROW
DECLARE
BEGIN
IF( :new.initiativeID != :old.initiativeID )
THEN
RAISE_APPLICATION_ERROR( -20001, 'Sorry Charlie. You can''t update the initiativeID column' );
END IF;
END;
当然,有人可以禁用触发器并发布更新。但我假设你并不是试图阻止攻击者,只是一段有缺陷的代码。
然而,根据您所看到的症状的描述,记录此表中列的更改历史似乎更有意义,以便您可以实际确定发生了什么,而不是猜测并试图堵住漏洞一一。例如,你可以这样做
CREATE TABLE TPM_INITIATIVES_HIST (
INITIATIVEID NUMBER NOT NULL,
NAME VARCHAR2(100) NOT NULL,
ACTIVE CHAR(1) NULL,
SORTORDER NUMBER NULL,
SHORTNAME VARCHAR2(100) NULL,
PROJECTTYPEID NUMBER NOT NULL,
OPERATIONTYPE VARCHAR2(1) NOT NULL,
CHANGEUSERNAME VARCHAR2(30),
CHANGEDATE DATE,
COMMENT VARCHAR2(4000)
);
CREATE TRIGGER trigger_name
BEFORE INSERT or UPDATE or DELETE ON TPM_INITIATIVES
FOR EACH ROW
DECLARE
l_comment VARCHAR2(4000);
BEGIN
IF( inserting )
THEN
INSERT INTO tpm_initiatives_hist( INITIATIVEID, NAME, ACTIVE, SORTORDER, SHORTNAME, PROJECTTYPEID,
OPERATIONTYPE, CHANGEUSERNAME, CHANGEDATE )
VALUES( :new.initiativeID, :new.name, :new.active, :new.sortOrder, :new.shortName, :new.projectTypeID,
'I', USER, SYSDATE );
ELSIF( inserting )
THEN
IF( :new.initiativeID != :old.initiativeID )
THEN
l_comment := 'Initiative ID changed from ' || :old.initiativeID || ' to ' || :new.initiativeID;
END IF;
INSERT INTO tpm_initiatives_hist( INITIATIVEID, NAME, ACTIVE, SORTORDER, SHORTNAME, PROJECTTYPEID,
OPERATIONTYPE, CHANGEUSERNAME, CHANGEDATE, COMMENT )
VALUES( :new.initiativeID, :new.name, :new.active, :new.sortOrder, :new.shortName, :new.projectTypeID,
'U', USER, SYSDATE, l_comment );
ELSIF( deleting )
THEN
INSERT INTO tpm_initiatives_hist( INITIATIVEID, NAME, ACTIVE, SORTORDER, SHORTNAME, PROJECTTYPEID,
OPERATIONTYPE, CHANGEUSERNAME, CHANGEDATE )
VALUES( :old.initiativeID, :old.name, :old.active, :old.sortOrder, :old.shortName, :old.projectTypeID,
'D', USER, SYSDATE );
END IF;
END;
然后就可以查询了TPM_INITIATIVES_HIST
查看一段时间内对特定行所做的所有更改。因此,您可以查看主键值是否正在更改,或者是否有人只是更改了非键字段。理想情况下,您可能有其他列可以添加到历史表中以帮助跟踪更改(即,可能有一些来自V$SESSION
这可能有用)。