Oracle:自增触发器。

3

在数据库中发现了以下触发器,它正在阻止插入唯一的varchar主键

CREATE OR REPLACE TRIGGER  "BI_PRIVILEGE" 
  before insert on "PRIVILEGE"               
  for each row  
begin   
  if :NEW."PRIVILEGE-ID" is null then 
    select "PRIVILEGE_SEQ".nextval into :NEW."PRIVILEGE-ID" from dual; 
  end if; 
end; 

这是一个自动生成编号器吗?我可以轻松地禁用它来解决我的问题,但是主键会有意想不到的负面影响吗?
实际上,我一直在寻找设置自动递增触发器以用于主键的代码,并且如果这是它的模板,我可以使用它。如果是这样,那么它可能是错误的,因为主键是特定的PRIVILEGE_ID而不是PRIVILEGE-ID,此外,在冲突的情况下,应该出现某种application_error,对吧?

你已经找到了问题,列名不正确。为什么要考虑禁用触发器(它是自增的)?为什么不直接纠正错误的代码呢? - Ben
@Ben 因为在这种情况下,主键是用于唯一字符串的。我无法想象自动递增在这种情境中会有用。 - Stumbler
1
如果这个触发器阻止了插入操作,那么它肯定被使用了,因此禁用它可能不是最好的方案。无论如何,值得思考的是,如果这个触发器可以阻止应用程序代码,那么数据库中是否存在任何事务问题。 - Ben
4个回答

4

好的,我明白了正在发生什么。对于你的问题,答案是绝对巨大的肯定。如果禁用此触发器,可能会产生很大的影响。

这个触发器存在的原因似乎是为了处理在插入到表中时没有提供主键值的情况。如果这种情况在代码中的任何地方出现,则删除触发器将破坏这些插入操作。

你需要做两件事。

  1. Correct the trigger, it's obviously broken; fix it:

    CREATE OR REPLACE TRIGGER  BI_PRIVILEGE
      before insert on PRIVILEGE              
      for each row  
    begin   
      if :NEW.PRIVILEGE_ID is null then 
        select PRIVILEGE_SEQ.nextval into :NEW.PRIVILEGE_ID from dual; 
      end if; 
    end; 
    

    If you're using Oracle 11G or greater then you can use this instead:

      if :NEW.PRIVILEGE_ID is null then 
        :NEW.PRIVILEGE_ID := PRIVILEGE_SEQ.nextval; 
      end if; 
    
  2. Work out whether this actually happens. If you do insert records without a primary key you need to find out why this happening and whether the behaviour is correct. If it is you're stuck with the trigger, otherwise fix that. If you never insert records without a primary key then you can disable the trigger.

    The quickest way of finding out may be to disable the trigger anyway but it would break your inserts. If this is a production database only you can tell whether it's worth it. I wouldn't personally.


“NOT NULLABLE”难道不足以保证主键始终填充其他数据吗? - Stumbler
主键始终声明为“NOT NULL”@Duncan。这不是问题;是的,您确保主键始终填写,但触发器正在处理那些未填写并在测试非空约束之前自动完成它的情况。您可以检查列中是否有单个数字。如果有,则可能已使用触发器。 - Ben

1
这个脚本会从一个序列中获取一个值,并将其放入新插入的行中。它的作用类似于自动编号。我认为应用程序代码依赖于此触发器来填充插入行的主键,在评估应用程序源代码之前,不建议删除它。
除非这是某种被遗忘的实验,否则应用程序代码很可能依赖于这个触发器/序列。
这是一个可接受的自增功能解决方案。参见:如何在Oracle上创建带有AUTO_INCREMENT的id?

1
在这种情况下,主键是用于唯一字符串的。我无法想象自动递增在这种情况下会有什么用处。
如果你的意思是“PRIVILEGE-ID”是一个varchar2列,那么你有些正确。一方面,数字也可以是字符串,所以它可以作为一个键。但是,如果键应该具有特定的字母和数字格式,单调递增的数字就不适合这个模式。
对我来说,关注点是IF语句。它表明有时应用程序填充键,而其他时候则由数据库默认。这很混乱。除此之外,有两个键源意味着序列不再保证唯一。现在你有可能生成的序列nextval会与先前手动分配的数字发生冲突。
怎么办?
如果您拥有一个具有良好覆盖自动化单元测试或集成测试的开发环境,答案很简单:禁用触发器,运行测试套件并查看哪些失败。如果这不描述您的设置(我有一种感觉它不会),那么禁用该触发器更加危险,因为您无法确信已经测试了可能填充表格的所有路径。

0
创建一个序列:
CREATE SEQUENCE SEQ_CM_LC_FINAL_STATUS
MINVALUE 1 MAXVALUE 999999999999999999999999999 
INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER  NOCYCLE;

添加触发器

CREATE OR REPLACE TRIGGER CM_LC_FINAL_STATUS_TRIGGER
BEFORE INSERT
ON CM_LC_FINAL_STATUS
FOR EACH ROW
BEGIN
:NEW.LC_FINAL_STATUS_NO := SEQ_CM_LC_FINAL_STATUS.NEXTVAL;
END;

第一步是在您的数据库中创建一个SEQUENCE,它是一个数据对象,多个用户可以访问以自动生成递增值。正如文档中所讨论的那样,Oracle中的序列可以防止同时创建重复值,因为多个用户在生成每个连续项之前被强制“轮流”使用。-

最后,我们将创建我们的SEQUENCE,稍后将用于实际生成唯一的自动递增值。-

虽然我们已经创建好了表并准备就绪,但我们的序列迄今为止只是闲置着,从未被使用过。这就是TRIGGERS发挥作用的地方。与现代编程语言中的事件类似,Oracle中的TRIGGER是在特定事件发生时执行的存储过程。通常,当需要进行清理时,会配置TRIGGER在更新表或删除记录时触发。-

在我们的情况下,我们希望在插入到CM_LC_FINAL_STATUS表之前执行我们的TRIGGER,确保我们的SEQUENCE递增,并将新值传递到我们的主键列。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接