Triggers são blocos de código PL/SQL que são executados automaticamente quando um determinado comando é executado numa tabela da base de dados a qual essa trigger esteja associada, assim como um INSERT, DELETE ou UPDATE. Elas normalmente são utilizadas para a realização de tarefas relacionadas a validações, acessibilidade, segurança e consistência de dados.

A utilização das triggers em nossas bases de dados é, de certa forma, uma melhoria para o código escrito, o que possibilita uma melhor manutenção quando necessário, já que teremos o código em um único local. A utilização de triggers também pode nos dar problemas com relação a desempenho da aplicação, já que, dependendo do caso, a aplicação pode ficar lenta quando estivermos inserindo 1000 registros, por exemplo. Mas em todo caso, devemos tomar alguns cuidados sobre sua implementação e uso. Com a sua utilização é possível garantir a execução de comandos para uma tabela em específico. Uma das recomendações da Oracle é que limitemos nossos códigos em no máximo 60 linhas. Se precisarmos de um código maior e para algo mais complexo, então o melhor que utilizemos procedures.

Quando podemos utilizar triggers?

Alguns dos principais motivos para a utilização de triggers estão listados abaixo:

  • Para garantir a segurança das informações;
  • Para casos de Auditoria, onde poderemos saber quais tabelas foram atualizadas e por qual usuário, por exemplo;
  • Para replicação de dados, onde podemos criar políticas de replicação síncrona para outras bases;
  • Para garantir a integridade das informações, onde podemos criar controles mais complexos para relacionamento entre tabelas;
  • Para o controle dos dados, no caso em que tenhamos tabelas associadas por chaves estrangeiras e que precisem ser atualizadas automaticamente.

Cuidados com a utilização de triggers

Um ponto ao qual devemos ter cuidado em relação à triggers é com o desempenho que nossas aplicações terão quando estas são disparadas, pois dependendo do caso em que elas estejam sendo utilizadas, poderá haver uma queda grande de desempenho do banco de dados e isso é algo que devemos evitar. Mas como?

Sabemos que para cada usuário da base de dados é criada uma sessão de logon, onde cada integrante terá suas particularidades em relação ao uso da base de dados, as quais foram definidas pelo DBA master. Mas digamos que um determinado usuárioA esteja querendo, por exemplo, inserir uma determinada quantidade de registros na base de dados sem querer utilizar uma trigger e não querendo que os outros usuários do banco, que possam estar trabalhando com a mesma tabela, sejam afetados pelas alterações que ele quer fazer. Então, eis que vem a seguinte pergunta: Podemos desabilitar, mesmo que temporariamente, uma trigger para uma determinada sessão?

A resposta para esta questão é simples. Não! Não podemos desabilitar uma trigger por sessão, pois uma trigger é um mecanismo do banco de dados que executa uma instrução SQL automaticamente quando um determinado evento ocorre. O motivo pelo qual não é possível desabilitar triggers em sessão se dá devido ao fato de que quando criamos uma trigger, a base de dados adiciona informações no System Catalog e systriggers sobre esta trigger. Além deste fato, tabelas de dicionários são armazenadas em memória para indicar as tabelas que possuem triggers definidas para elas.

E esta realidade nos leva a uma nova questão: Mas então como desabilitar a trigger e fazer as inserções que precisamos sem que afete a terceiros?

Para esta questão, existem algumas soluções onde não estaremos “desabilitando” a trigger, mas permitiremos que ela dispare normalmente, mas sem que sua lógica afete a nossa sessão e consequentemente, não afete aos outros usuários. Então agora vamos ver como isso seria possível.

Driblando obstáculos!

Neste exemplo trabalharemos com triggers DML, que serão disparadas em casos de inserção, deleção ou edição de registros. Para isso, criaremos uma tabela com alguns registros inicialmente, ou caso você já tenha alguma base de dados pronta, pode utilizá-la também fazendo as devidas mudanças que forem necessárias e posteriormente criaremos uma trigger para inserção, edição e deleção de registros da tabela em questão.

Nota: Caso queira saber mais sobre outros tipos de triggers, não deixe de conferir esse artigo sobre triggers DDL.

Vamos então criar um exemplo simples de utilização, onde estamos interessados no preço de determinados produtos que podem passar por mudanças e inserção de novos produtos na tabela produtos. Como podemos observar, será necessário também manter um registro de atualização de valores e outras informações numa tabela a parte, com isso, criaremos também a tabela histórico_preco_produto. Começaremos então com a criação das tabelas de nossa base, conforme aListagem 1.

Listagem 1. Criação das tabelas de produtos e histórico_preco_produto.


CREATE TABLE historico_preco_produto 
  (
  produto_id number(5),
  produto_nome varchar2(50),
  produto_descricao varchar2(150), 
  produto_preco_unitario number(7,2) 
  ); 
   
  CREATE TABLE produtos 
  (
  produto_id number(5),
  produto_nome varchar2(32), 
  produto_descricao varchar2(150), 
  produto_preco_unitario number(7,2)
   );

Em seguida, iremos popular a tabela produtos com alguns registros antes de criarmos nossa trigger. A população das tabelas se dará de acordo com a Listagem 2.

Listagem 2. Populando a tabela de produtos com registros iniciais.


  INSERT INTO produtos VALUES (1, 'leite', 'bebida nutritiva', '2.50'); 
  INSERT INTO produtos VALUES (2, 'carne bovina', 'musculo', '10.00'); 
  INSERT INTO produtos VALUES (3, 'ovos', 'item vendido por unidade', '2.50'); 
  INSERT INTO produtos VALUES (4, 'pão', '10 unidades', '3.50'); 
  INSERT INTO produtos VALUES (5, 'laranja', 'fruta rica em vitamina C, quantidade mínima 12 unidades', '5.00'); 
  INSERT INTO produtos VALUES (6, 'feijão', 'Alimento rico em ferro', '4.50');
  INSERT INTO produtos VALUES (7, 'café', 'para incentivar os estudos', '3.50');
  INSERT INTO produtos VALUES (8, 'queijo', 'Alimento diferenciado', '8.50');
  INSERT INTO produtos VALUES (9, 'presunto', 'presunto de porco', '6.50');
  INSERT INTO produtos VALUES (10, 'maçã', 'Maçã vermelha', '2.50');

Agora que temos nossas tabelas criadas e a tabela de produtos já populada com alguns registros, é hora de criarmos nossa trigger que será utilizada tanto para atualizar quanto para deletar e inserir os registros na tabela de produtos para então inserir na tabela de histórico_preco_produtos um novo registro, de acordo com a Listagem 3.

Listagem 3. Criação da trigger historico_preco_produto_trigger.


CREATE OR REPLACE
 TRIGGER historico_preco_produto 
 BEFORE INSERT OR DELETE OR UPDATE ON produtos 
 FOR EACH ROW
 BEGIN
     IF UPDATING THEN
               INSERT INTO historico_preco_produto (produto_id, produto_nome, produto_descricao, produto_preco_unitario) VALUES ( :old.produto_id, :old.produto_nome, :old.produto_descricao, :old.produto_preco_unitario);
     ELSEIF DELETING THEN 
               INSERT INTO historico_preco_produto (produto_id, produto_nome, produto_descricao, produto_preco_unitario) VALUES ( :old.produto_id, :old.produto_nome, :old.produto_descricao, :old.produto_preco_unitario);
     ELSEIF INSERTING THEN 
               INSERT INTO historico_preco_produto (produto_id, produto_nome, produto_descricao, produto_preco_unitario) VALUES ( :old.produto_id, :old.produto_nome, :old.produto_descricao, :old.produto_preco_unitario);
     END IF;
 END;

Como podemos perceber, esta trigger será disparada antes de ser realizada uma das três operações que são atualização, deleção ou adição de registros na tabela de produtos, onde primeiramente irá registrar as informações antigas que estavam nos registros que passaram por alguma alteração. Este é um exemplo básico de como realizar uma auditoria de informações, onde poderíamos acrescer as informações para saber quem realizou as operações, por exemplo. Agora que temos nossa trigger criada, vamos realizar a atualização de alguns registros para que estes constem na tabela de histórico dos produtos, de acordo com a Listagem 4.

Listagem 4. Atualização de registros antes de “desabilitar” a trigger.

UPDATE PRODUTOS SET produto_preco_unitario = 9.50 WHERE produto_id = 8; 
  UPDATE PRODUTOS SET produto_preco_unitario = 4.50, produto_descricao = “queijo prato fatiado” WHERE produto_id = 7; 
  UPDATE PRODUTOS SET produto_preco_unitario = 6.50, produto_descricao = “maçã verde” WHERE produto_id = 10; 
  UPDATE PRODUTOS SET produto_nome = “presunto de porco”, produto_descricao = “presunto suíno”, produto_preco_unitario = 8.50 WHERE produto_id = 9; 

Após a atualização dos registros podemos visualizar na tabela historico_preco_produto as informações que foram registradas, através de um select na tabela para conferir as informações que foram passadas. Podemos ver este select na Listagem 5.

Listagem 5. Instrução select para visualização dos registros atualizados.


  SELECT *  FROM historico_preco_produto;

Agora temos tudo funcionando corretamente, certo? Não, pois a nossa intenção aqui é mostrar uma forma de “desabilitar” a utilização da trigger para um determinado usuário da base de dados sem que haja interferência para os demais usuários. Uma forma de “desabilitar” a trigger é criando uma package onde passaremos uma variável do tipo boolean para dizer se poderá ou não utilizar aquela trigger.

Criaremos nossa package da seguinte forma, como mostra a Listagem 6.

Listagem 6. Criação da package global_package.


  CREATE PACKAGE global_package
  IS
     dispara_minha_trigger BOOLEAN := TRUE;
  END;
  /

Após criarmos o nosso package, é hora de fazermos a nossa verificação para a utilização da trigger em questão na hora em que formos inserir novos dados. A modificação que será realizada na trigger, de acordo com a Listagem 7, é apenas fazendo uma verificação do package após o BEGIN, onde verificamos com relação a utilização da trigger. Percebam que a trigger em nenhum momento foi desabilitada, ela é disparada normalmente, mas a sua lógica só será efetivada se passarmos o valor FALSE para a variável.

Listagem 7. Mudanças realizadas na trigger principal.


  CREATE OR REPLACE
 TRIGGER historico_preco_produto 
 BEFORE INSERT OR DELETE OR UPDATE ON produtos 
 FOR EACH ROW
 BEGIN
  if not global_package.dispara_minha_trigger then
  return; 
     end if; 
   
  [...continuação do código]
 END;

Percebam que a condição que foi criada verifica se a variável no package é verdadeira ou falsa. Após essa verificação, se a variável tiver o valor true, a nossa instrução condicional fará a verificação e retornará false e assim sairá da trigger sem realizar sua lógica. Já no caso contrário, onde o valor da variável for false, receberíamos true na condição e continuaríamos com a lógica da trigger normalmente.

Agora para que tudo funcione corretamente, como DBA devemos dar permissão aos usuários que realmente terão acesso a este package. Sendo assim, eles irão utilizar a trigger quando realmente for necessário para eles e, o melhor de tudo, é que não haverá problemas para a utilização da trigger por outros usuários da base de dados.

Com isso finalizamos este artigo, onde pudemos sanar a dúvida que existe com relação a inativar uma trigger temporariamente por sessão de usuário. Vimos que esta prática não é permitida, mas é possível que se recorra a outros artifícios para realizarmos nossas tarefas sem que a lógica da trigger seja executada. Esperamos que tenha sido útil este artigo e até a próxima.