Situações onde o bloco catch não é executado

Publicado: 8 de setembro de 2009 em T-SQL
Tags:

Galera,

 

Hoje vou falar sobre um
assunto bem interessante: Situações onde o bloco catch não é executado. Essa
semana eu estava lendo sobre este assunto e achei útil mostrar em que situações
o bloco catch não é executado.

 

Abaixo temos alguns exemplos:

 

KILL ou Timeout do comando

 

Imagine ter um código onde
você realiza vários updates em uma ou várias tabelas dentro de um bloco begin
try e, caso exista algum problema durante a atualização, a transação deve ser
revertida e a linha e mensagem de erro devem ser logadas em uma tabela
destinada ao log de erros.

 

Bom, vamos criar nossa base de dados e as tabelas conforme
script abaixo:

–CRIA E COLOCA EM USO O DATABASE

CREATE DATABASE
DB_TESTE

GO

 

USE DB_TESTE

GO

 

–CRIA TABELA QUE VAI ARMAZENAR OS ERROS OCORRIDOS

CREATE TABLE
TB_ERROR(ELINE INT
, 
EMESSAGE nvarchar(2048))

 

–CRIA A TABELA PARA TESTAR O UPDATE

CREATE TABLE
CLIENTE ( ID INT, NOME VARCHAR(10), STATUS CHAR(1))

GO

 

–ADICIONA UMA CHECK PARA O CAMPO STATUS ( A = ATIVO, I =
INATIVO )

ALTER TABLE
CLIENTE  WITH
CHECK ADD  CONSTRAINT
CK_STATUS CHECK (
STATUS = ‘A’ OR STATUS = ‘I’)

GO

 

–POPULA A TABELA

INSERT INTO
CLIENTE( ID,
NOME, STATUS ) VALUES ( 1, ‘DEMÉTRIO’, ‘A’ )

INSERT INTO
CLIENTE( ID,
NOME, STATUS ) VALUES ( 2, ‘MARIA’, ‘A’ )

INSERT INTO
CLIENTE( ID,
NOME, STATUS ) VALUES ( 3, ‘JOSÉ’, ‘A’ )

INSERT INTO
CLIENTE( ID,
NOME, STATUS ) VALUES ( 4, ‘JOÃO’, ‘I’ )

INSERT INTO
CLIENTE( ID,
NOME, STATUS ) VALUES ( 5, ‘PEDRO’, ‘I’ )

 

–VERIFICA OS DADOS INSERIDOS

SELECT * FROM CLIENTE

Bom, conforme
podemos verificar, o script abaixo realiza dois updates na tabela, sendo que o
segundo gera um erro. Ao capturar o erro, o bloco catch realiza o rollback da
transação e insere a linha e mensagem de erro na tabela TB_ERROR.

BEGIN TRY

     

      BEGIN TRAN

           

            –ATUALIZA
TODOS OS DADOS DO CAMPO NOME DA TABELA

            UPDATE
CLIENTE SET NOME +=
‘_’

           

            –ATUALIZA
TODOS OS STATUS PARA ‘L’, VAI GERAR ERRO POR CAUSA DA CHECK CONSTRAINT

            UPDATE CLIENTE SET STATUS = ‘L’

     

      COMMIT

     

END TRY

BEGIN CATCH

 

      –SE HOUVE ERRO,
REVERTE A TRANSAÇÃO E LOGA O ERRO NA TABELA

      IF @@TRANCOUNT > 0

            ROLLBACK

 

      INSERT INTO TB_ERROR ( ELINE, EMESSAGE )

      SELECT

            ERROR_LINE(),

            ERROR_MESSAGE()        

           

END CATCH

 

 

Como podemos
verificar no select abaixo, o primeiro update é revertido e um registro é gravado
na tabela de log.

SELECT *
FROM CLIENTE

SELECT * FROM TB_ERROR

–LIMPA O LOG DE ERROS

DELETE TB_ERROR

Até agora sem problemas. Mas, e se alguém executar um kill ou
mesmo existir um timeout na conexão que está executando o update?

A transação é revertida, não através do rollback contido no
bloco catch, mas sim porque esse é procedimento executado quando utilizamos um
kill contra algum processo. No entanto, note que o insert na tabela de log não
é executado, ou seja, isso é uma prova que o bloco catch não foi executado.

Abra duas conexões no SSMS e execute o código abaixo:

BEGIN TRY

     

      BEGIN TRAN

           

            –ATUALIZA
TODOS OS DADOS DO CAMPO NOME DA TABELA

            UPDATE CLIENTE SET NOME += ‘_’

           

–AGUARDA 5 MINUTOS
PARA DAR TEMPO DE REALIZAR O KILL

            WAITFOR
DELAY ’00:05:00′

           

            –ATUALIZA
TODOS OS STATUS PARA ‘L’, VAI GERAR POR CAUSA DA CHECK CONSTRAINT

            UPDATE CLIENTE SET STATUS = ‘L’

     

      COMMIT

     

END TRY

BEGIN CATCH

 

      –SE HOUVE ERRO,
REVERTE A TRANSAÇÃO E LOGA O ERRO NA TABELA

      IF @@TRANCOUNT > 0

            ROLLBACK

 

      INSERT INTO TB_ERROR ( ELINE, EMESSAGE )

      SELECT

            ERROR_LINE(),

            ERROR_MESSAGE()        

           

END CATCH

Verifique o spid da
conexão que está o script acima e na outra janela do SSMS execute o comando
KILL passando o spid da conexão acima.

Após matar o
processo acima, volte na janela que encontra-se o script acima e veja que o SQL
Server gerou o seguinte erro.

Msg 0, Level 11, State 0, Line 0

A severe error occurred on the
current command.  The results, if any,
should be discarded.

Msg
0, Level 20, State 0, Line 0

A severe error occurred on the current command.  The results, if any, should be discarded.

Agora, verifique que
a transação foi revertida mas que nenhuma linha foi inserida no log de erros:

SELECT *
FROM CLIENTE

SELECT * FROM TB_ERROR

Esse é um dos casos
onde o catch não é executado, o mesmo acontece quando existe um timeout,
devemos ficar atento quando estivermos utilizando o catch e fazendo algum
tratamento dentro do mesmo.

É isso ai, num próximo post irei mostrar outras situações onde o
bloco catch não é executado.

Abraços

Anúncios
comentários
  1. Laerte disse:

    Show de bola meu amigo !!!..Tratamento de erros é uma prática indispensável em qq ambiente…e sua explicação foi perfeita !!!!

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s