如果有子表填充有引用该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
内容可能有用)。