包含变异表(mutating table)的触发器

我想问,为什么,直接创建before updata的行级触发器,会导致锁定?

最新回复

  • B060815 (2007-6-23 08:43:06)
    触发器中SQL语句不能:读取或更新触发语句的任何变异表也包括触发表本身,读取或更新该触发表的约束表的主键列、唯一性键列或外键列但是如果需要也可以更新其他列。这些限制约束适用于所有行级触发器。但有个特例就是如果INSERT只影响一行记录那么定义在这行上的行级BEFORE和AFTER触发器就不会将这个触发表当作变异表。
  • B060815 (2007-6-23 09:11:30)
    那么要想实现就意味这不能在行级触发器里查询该表,但是可以在语句级触发器里查询它。但是不能简单的将它设计成一个语句级触发器因为我们需要在触发器主体中使用:new.major的值。这个问题的解决办法就是创建2个触发器一个行级的一个语句的,在行级里记录:new.major的值但是不查询表,查询在语句里实现。那么怎么记录值呢,就要通过一个包了。

    create or replace package studentdata as
    type t_majors is table of students.major%type index by binary_integer;
    type t_ids is table of students.id%type index by binary
    v_studentmajors t_majors;
    v_studentids t_ids;
    v_numbertries binary_integer:=0;
    end studentsdata;

    create or replace trigger rlimitmajors
    before insert or update of major on students
    for each row
    begin
    studentdata.v_numbertries:=studentdata.v_numbertries+1;
    studentdata.v_studentmajors(studentdata.v_numberies):=:new.major;
    studentdata.v_studentids(studentdata.v_numberies):=:new.id;
    end rlimitmajors;

    create or replace trigger slimitmajors
    after insert or update of major on students
    declare
    v_maxstudents constant number:=2;
    v_currentstudents number;
    v_studentid student.id%type;
    v_major students.major%type;
    begin
    for v_loopindex in 1..studentdata.v_numberies loop
    v_studentid:=studentdata.v_studentids(v_loopindex);
    v_major:=studentdata.v_studentmajors(v_loopindex);
    select count(*) into v_currentstudents from students where major=v_major;
    if v_currentstudents>v_maxstudents then
    raise_application_error(-20000,'too many students for major '||v_major||'because of student'||v_studentid);
    end if;
    studentdata.v_numberies:=0;
    end slimitmajors;
  • B060815 (2007-6-23 09:17:58)
    确保变量成为全局变量的唯一方法就是将它存放在某个包中
  • B060815 (2007-6-23 09:40:53)
    也可以使用AutoCommit方法解决。例如: CREATE OR REPLACE TRIGGER TRIGGER_NAME [BEFORE|AFTER] ACTION ON TABLE_NAME FOR EACH ROW DECLARE PRAGMA AUTONOMOUS_TRANSACTION BEGIN ...... COMMIT; END;
  • declare64 (2007-6-23 16:09:24)
    谢谢楼上的回答,好详细啊;
      最后一个没有看懂,在触发器里面,应该不能包含事务处理语句的;还有pragma autonomous_transaction 是什么意思?
  • valenwon (2007-6-23 18:04:48)
    AUTONOMOUS TRANSACTION(自治事务)
    数据库事务是一种单元操作,要么是全部操作都成功,要么全部失败。在Oracle中,一个事务是从执行第一个数据管理语言(DML)语句开始,直到执行一个COMMIT语句,提交保存这个事务,或者执行一个ROLLBACK语句,放弃此次操作结束。

    事务的“要么全部完成,要么什么都没完成”的本性会使将错误信息记入数据库表中变得很困难,因为当事务失败重新运行时,用来编写日志条目的INSERT语句还未完成。

    针对这种困境,Oracle提供了一种便捷的方法,即自治事务。自治事务从当前事务开始,在其自身的语境中执行。它们能独立地被提交或重新运行,而不影响正在运行的事务。正因为这样,它们成了编写错误日志表格的理想形式。在事务中检测到错误时,您可以在错误日志表格中插入一行并提交它,然后在不丢失这次插入的情况下回滚主事务。

    因为自治事务是与主事务相分离的,所以它不能检测到被修改过的行的当前状态。这就好像在主事务提交之前,它们一直处于单独的会话里,对自治事务来说,它们是不可用的。然而,反过来情况就不同了:主事务能够检测到已经执行过的自治事务的结果。

    要创建一个自治事务,您必须在匿名块的最高层或者存储过程、函数、数据包或触发的定义部分中,使用PL/SQL中的PRAGMA AUTONOMOUS_TRANSACTION语句。在这样的模块或过程中执行的SQL Server语句都是自治的。

    触发无法包含COMMIT语句,除非有PRAGMA AUTONOMOUS_TRANSACTION标记。但是,只有触发中的语句才能被提交,主事务则不行。

    列表A展示了对一个简单但灵活的错误日志表格所作的CREATE TABLE和CREATE SEQUENCE语句。

    CREATE TABLE errorlog ( errorlog_id NUMBER, logged_on TIMESTAMP DEFAULT SYSTIMESTAMP, logged_by VARCHAR2(30) DEFAULT USER, num1 NUMBER, num2 NUMBER, num3 NUMBER, text1 VARCHAR2(1000), text2 VARCHAR2(1000), text3 VARCHAR2(1000) );CREATE SEQUENCE errorlog_seq START WITH 1 INCREMENT BY 1;

    列表B是一个独立的存储过程,用于更新错误日志表格。

    CREATE OR REPLACEPROCEDURE log_error ( n1 IN NUMBER:=NULL, t1 IN VARCHAR:=NULL, n2 IN NUMBER:=NULL, t2 IN VARCHAR:=NULL, n3 IN NUMBER:=NULL, t3 IN VARCHAR:=NULL )IS PRAGMA AUTONOMOUS_TRANSACTION;BEGIN INSERT INTO errorlog (errorlog_id, num1, num2, num3, text1, text2, text3) VALUES (errorlog_seq.NEXTVAL, n1, n2, n3, t1, t2, t3); COMMIT;END;

    该过程接受最多三个数字和三个文本变量,然后将它们和时间戳以及调用过程的用户一起储存在表格中。

    要测试这个过程,就要更新(UPDATE)或删除(DELETE)表格中的某些行;这就引发了主事务。然后执行存储过程,将您选择的要记入日志的数据传递给它。最后,重新运行主事务,选择(SELECT)错误日志表格,您的日志条目仍会在那儿。
本文来自:http://blog.oracle.com.cn/html/58/t-120858.html
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值