Desenvolvimento - SQL

Tratamento de Erros com o Try/Catch

A algum tempo atrás, encontrei uma thread no MSDN, com uma pergunta de um desenvolvedor que estava tendo problemas ao efetuar o tratamento de erros com um bloco Try/Catch.

por Luiz Phellipe Euzebio Damião



A algum tempo atrás, encontrei uma thread no MSDN, com uma pergunta de um desenvolvedor que estava tendo problemas ao efetuar o tratamento de erros com um bloco Try/Catch. Como já tive um problema semelhante na empresa em que trabalho, então, resolvi comentar um pouco sobre o assunto.

Quando usamos o bloco Try/Catch para tratamento de erros, precisamos ter pleno conhecimento dos tipos de erros que são ou não tratados por ele.

Um exemplo de erro não tratado é o causado quando o SQL Server não encontra um objeto referenciado em alguma das instruções do lote.  Exemplo:

-------------------------------------------

-- Faz referencia a um objeto que não existe

-------------------------------------------

Begin Try

   Begin Tran

   -- Faz o Select em uma tabela que não existe

   Select 1 From TabelaInexistente

   --Conclui a Transação

   Commit Tran

End Try

Begin Catch

   Select ERROR_MESSAGE()

   -- Verifica se existe alguma transação aberta

   If @@Trancount > 0

      Rollback Tran

End Catch

Go

--

Select @@TRANCOUNT As "@@Trancount"

Se executar o script acima, você poderá notar que a transação foi aberta porém não foi commitada e nem revertida, logo, significa que o SQL Srver abortou o "batch"(lote de instruções) assim que encontrou o erro na resolução do nome do objeto (objeto Inexistente). Esse erro é imediatamente retornado ao bloco chamador do "batch".

Como no exemplo acima o Try/Catch está diretamente no primeiro nível de "batch"s", o erro será retornado à aplicação. Entretanto, se a instrução que gerou o erro estivesse dentro de uma procedure ou function, esse erro seria retornado ao "batch" chamador das mesmas e então, seria passivel de tratamento pelo Try/Catch como podemos ver no exemplo a seguir.

-------------------------------------------

-- Cria uma Proc exatamente com a mesma instrução que gerou erro

-------------------------------------------

Create Procedure ObjetoInexistenteSel

As

Begin Try

   Begin Tran

   -- Faz o Select em uma tabela que não existe

   Select 1 From TabelaInexistente

   --Conclui a Transação

   Commit Tran

End Try

Begin Catch

   Select "Bloco Catch Interno" As BlocoCatch, ERROR_MESSAGE() As Erro

   -- Verifica se existe alguma transação aberta

   If @@Trancount > 0

      Rollback Tran

End Catch

-- Retorna o Contador de Transações

Select @@TRANCOUNT

Go

-------------------------------------------

-- Agora chamaremos a proc em um bloco Try

-------------------------------------------

Begin Try

   Exec ObjetoInexistenteSel

End Try

Begin Catch

   Select "Bloco Catch Externo" As BlocoCatch, ERROR_MESSAGE() As Erro

   -- Verifica se existe alguma transação aberta

   If @@Trancount > 0

      Rollback Tran

End Catch

-- Retorna o Contador de Transações

Select @@TRANCOUNT

Go  

Note que o erro ocorrido na procedure, apenas foi capturado no bloco Catch externo(chamador da procedure).

Além disso, erros com severidade igual ou menor a 10 também não são tratados pelo Catch.

Set Nocount on

Go

Print "-------------------------------------------"

Print "-- Severidade igual a 10 que não é capturado pelo Catch"

Print "-------------------------------------------"

Begin Try

   RaisError (N"Erro Não tratado Pelo Try", 10, 1)

   Print " --> Continua a Execução do Bloco Try"

End Try

Begin Catch

   Print " --> Trata o Erro: " + Error_Message()

End Catch

Go

Print ""

Print "-------------------------------------------"

Print "-- Severidade maior do que 10 que é capturado pelo Catch"

Print "-------------------------------------------"

Begin Try

   RaisError (N"Erro tratado Pelo Try", 11, 1)

   Print " --> Continua a Execução do Bloco Try"

End Try

Begin Catch

   Print " --> Trata o Erro: " + Error_Message()

End Catch

No primeiro caso (erro com severidade igual a dez), apesar de mostrar a mensagem que foi inserida no RaiseError, o bloco Try continua sendo executado normalmente. Já no segundo caso, com severidade igual a onze, a execução do bloco try é finalizada quando chega no RaiseError e então o bloco Catch correspondente passa a ser executado.

Existem mais alguns casos em que o erro não pode ser tratado pelo bloco Catch. São eles:

Erros de compilação ou de sintaxe, porém, quando há algum destes erros, as instruções nem chegam a serem executadas

Interrupções solicitadas pelo cliente, (aplicativo que solicitou a execução de uma query) ou sessões finalizadas pelo comando KILL.

Erros com severidade igual ou maior a 20 que finalizem a conexão com o banco

Luiz Phellipe Euzebio Damião

Luiz Phellipe Euzebio Damião - Colunista do Linha de Código (www.linhadecodigo.com.br)