触发器里面before和after的区别

   关键字beforeafter用于标识触发时间,顾名思义,before代表触发器里面的命令在DML修改数据之前执行,after代表触发器里面的命令在DML修改数据之后执行。

   读者可以结合应用场景选择使用before或者after

   下面编者分别给出beforeafter的举例。

        

         before举例:

   在emp表上面创建触发器,当输入的工资小于100时,自动将工资修改为100

         create or replace trigger tri_emp_sal_check
         before INSERT OR UPDATE ON emp
         for each row
         BEGIN
             IF
 :new.sal <100 THEN
                 :new.sal :=100;
             END IF;
         END;


   执行DML语句

         update emp set sal =90 where empno =3030;

         commit;

   发现工号3030员工的工资成功修改为100

   

   上面的触发器,我们尝试将before修改为after。编译的时候报错,不能通过。错误信息如下:

   触发器里面before和after的区别

   编者前面已经说过,after代表触发器里面的命令在DML修改数据之后执行,既然DML操作对数据的更改已经完成,当然不允许再修改new对象的属性值了,所以此处编译不通过。

 

        after举例:

   在emp表上面创建触发器,当修改员工工资时,记录日志。为了更明显的显示效果,编者在此触发器中使用了自治事务。并且在emp表的sal列上增加了check约束,限制sal的值大于等于100

       create or replace trigger tri_emp_sal_change
     
after UPDATE ON emp
     
for each row
       DECLARE
      V_ID 
NUMBER;
      
pragma autonomous_transaction;
       BEGIN
        
IF updating('SAL')THEN
            
SELECT LOG_ID.NEXTVAL INTO V_ID FROM DUAL;
            
insert into log
             (ID,CONTENT, IP, COMPUTERNAME)
            
values
             (v_ID,
              :
new.empno ||'工资' ||'' || :old.sal ||'变更为' || :new.sal,
              sys_context('userenv','ip_address'),
              sys_context('userenv','terminal'));
             
commit;
         
END IF;
        END;

   接着编者执行如下update命令

         update emp set sal =90 where empno =3030;

   报违反检查约束条件错误,如下图所示。

   触发器里面before和after的区别

   编者查看log表,发现log表为空。如下图所示。

 触发器里面before和after的区别

   说明使用after的情况下,触发器里面的命令在DML修改数据之后执行,此时log中无记录,是因为DML修改数据时违反检查约束条件,触发器里面的命令没有机会执行。


   接着编者将触发器中的after替换成before

   执行相同的update命令

         update emp set sal =90 where empno =3030;

   同样违反检查约束条件,报错如下图所示。

   触发器里面before和after的区别

         编者接着查询log表,发现成功记录了修改日志。

触发器里面before和after的区别

   说明使用before的情况下,触发器里面的命令在DML修改数据之前执行,此处虽然DML修改数据时违反检查约束条件,没有执行成功,但是由于触发器里面的命令先于DML修改数据之前执行,并且此处使用了自治事务,使得触发器里面的命令得以成功执行。

   到底应该使用before还是after,要根据具体情况而定,一般需要更改要操作的数据时使用before。如果记录日志要使用after。只有使用了after才能确保DML语句成功执行,这样记录日志才有意义。

上一篇:到底应该使用count(*) 还是count(1)


下一篇:单行子查询返回多个行