Para melhor visualização, recomendo resolução de no mínimo 1280 x 800 e navegador Mozilla Firefox


quarta-feira, 3 de agosto de 2011

Definindo a ordem de execução de triggers no Oracle 11g ...

Por Eduardo Legatti

Olá,

Até o Oracle 11g, não se podia determinar a ordem de execução de triggers do mesmo tipo para uma tabela. Por exemplo, se temos 3 triggers em uma tabela na qual todas são BEFORE INSERT, qual será a ordem de execução das mesmas? A resposta é: impossível determinar, pois se você tiver várias triggers do mesmo tipo na tabela, então o Oracle escolherá uma ordem arbitrária e randômica para executá-las. Então dependendo da regra de negócio existente, isso poderia ser um problema ou não, pois a solução seria criar uma única trigger do tipo em questão e colocar toda a regra de negócio (PL/SQL) nela. A desvantagem nesse caso seria apenas de cunho administrativo e de manutenção, pois a trigger poderia ficar imensa, complexa e de difícil compreensão.

Na minha visão, a vantagem de se ter mais de uma trigger seria a de trazer mais praticidade e modularidade de forma a separar a regra de negócio de acordo com o objetivo de cada uma, além de trazer uma certa flexibilidade na hora realizar manutenções no código. Imagina um cenário onde existe uma única trigger que, além de realizar grande parte da regra de negócio, ainda realiza operações para geração de logs de transação. Veja a flexibilidade se criássemos 2 triggers: uma para a regra de negócio em si e outra para geração de logs de transação. Alguém um dia poderia sugerir: "A rotina está muito lenta hoje, acho melhor desabilitarmos a trigger que realiza a geração dos logs de transação" Fácil não?


No mais, neste artigo irei demonstrar que com o Oracle 11g podemos determinar a ordem de execução das triggers de uma tabela que são de um mesmo tipo. Na criação de uma trigger no Oracle 11g, existe uma nova cláusula chamada "follows" que nos permitirá definir a ordem de execução das mesmas.

No primeiro exemplo abaixo, irei criar 3 triggers do tipo BEFORE INSERT sem definir uma ordem de execução.

C:\>sqlplus scott/tiger

SQL*Plus: Release 11.2.0.1.0 Production on Qua Ago 3 21:34:36 2011

Copyright (c) 1982, 2010, Oracle. All rights reserved.

Conectado a:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> create table t1 (id number);

Tabela criada.

SQL> create or replace trigger trg_teste_01
2 before insert on t1
3 for each row
4 begin
5 dbms_output.put_line('trigger trg_teste_01');
6 end;
7 /

Gatilho criado.

SQL> create or replace trigger trg_teste_02
2 before insert on t1
3 for each row
4 begin
5 dbms_output.put_line('trigger trg_teste_02');
6 end;
7 /

Gatilho criado.

SQL> create or replace trigger trg_teste_03
2 before insert on t1
3 for each row
4 begin
5 dbms_output.put_line('trigger trg_teste_03');
6 end;
7 /

Gatilho criado.

Após a criação da tabela e das triggers, irei inserir um registro na tabela T1.

SQL> set serveroutput on
SQL> insert into t1 values (1);
trigger trg_teste_03
trigger trg_teste_02
trigger trg_teste_01

1 linha criada.

Perceberam que a trigger trg_teste_03 foi acionada primeiro? Quem garante que a mesma será executada primeiro na próxima vez? Bom, no segundo exemplo abaixo irei criar novamente as triggers só que, agora, definindo a ordem de execução: trg_teste_01, depois trg_teste_02 e depois trg_teste_03.

SQL> create or replace trigger trg_teste_01
2 before insert on t1
3 for each row
4 begin
5 dbms_output.put_line('trigger trg_teste_01');
6 end;
7 /

Gatilho criado.

SQL> create or replace trigger trg_teste_02
2 before insert on t1
3 for each row
4 follows trg_teste_01
5 begin
6 dbms_output.put_line('trigger trg_teste_02');
7 end;
8 /

Gatilho criado.

SQL> create or replace trigger trg_teste_03
2 before insert on t1
3 for each row
4 follows trg_teste_02
5 begin
6 dbms_output.put_line('trigger trg_teste_03');
7 end;
8 /

Gatilho criado.

SQL> insert into t1 values (2);
trigger trg_teste_01
trigger trg_teste_02
trigger trg_teste_03

1 linha criada.

Pronto. Podemos ver que as mesmas foram acionadas de acordo com a ordem que eu havia definido anteriormente. Poderíamos inclusive desabilitar uma das triggers que não haveria problema nenhum:
SQL> alter trigger trg_teste_02 disable;

Gatilho alterado.

SQL> insert into t1 values (3);
trigger trg_teste_01
trigger trg_teste_03

1 linha criada.

Agora, caso alguma trigger que é dependente de outra for dropada, aí sim teremos problemas pois não conseguiremos realizar algumas operações até que o problema seja sanado.

SQL> drop trigger trg_teste_02;

Gatilho eliminado.

SQL> select object_name,status from user_objects where object_type='TRIGGER';

OBJECT_NAME STATUS
------------------------------ -------
TRG_TESTE_01 VALID
TRG_TESTE_03 INVALID


SQL> insert into t1 values (3);
insert into t1 values (3)
*
ERRO na linha 1:
ORA-04045: erros durante a recompilação/revalidação de SCOTT.TRG_TESTE_03
ORA-04098: gatilho 'SCOTT.TRG_TESTE_03' é inválido e a revalidação falhou

SQL> drop table t1;
drop table t1
*
ERRO na linha 1:
ORA-00604: ocorreu um erro no nível 1 SQL recursivo
ORA-04045: erros durante a recompilação/revalidação de SCOTT.TRG_TESTE_03
ORA-04098: gatilho 'SCOTT.TRG_TESTE_03' é inválido e a revalidação falhou

SQL> alter trigger trg_teste_03 disable;

Gatilho alterado.

SQL> insert into t1 values (4);
trigger trg_teste_01

1 linha criada.

SQL> drop table t1;

Tabela eliminada.



6 comentários:

Fabio Ishii disse...

Olá Eduardo!! Eu tinha a impressão anteriormente que a ordem de execução era definida pelo id do objeto... lembro que em bases de desenvolvimento ou de produção qdo eram rodados os scripts funcionavam na ordem dos mesmo, porém no caso de um import novo, essa ordem não era mais respeitada talvez pela criação do import ser diferente...Grande material
Abraços
Fabio Ishii

Emerson disse...

E ai Legatti!
Maneiro essa implementação a partir do oracle 11g.Parabéns mais uma vez por um post de ótima qualidade.

Emerson
DBA Jr

Eduardo Legatti disse...

Olá Fábio,

Tudo bem?? Poisé, realmente não haveria como garantir isso, ainda mais após uma importação ;-)

Abraços e até mais...

Eduardo Legatti disse...

Olá Emerson,

Esta new feature do 11g veio mesmo na hora certa ;-)

Abraços e até mais...

Sakamoto disse...

Olá Eduardo !

Recurso interessante... Pra falar a verdade não sabia que podia criar varias trigger pro mesmo evento...Pensei que fosse possível apenas uma... Bom, agora eu sei que até pra ordenar a execução...

Att,

Sakamoto

MyTraceLog - Registro de um DBA
http://mytracelog.blogspot.com

Rodrigo Santana disse...

Realmente muito interessante essa feature, mais uma vez parabéns!!
Um Abraço

Postagens populares