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ãoA 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
- Diferenças entre SEQUENCES x IDENTITY no Microsoft SQL Server 2012SQL
- Utilizando FILETABLE no SQL Server 2012SQL Server
- Utilizando SEQUENCES no Microsoft SQL Server 2012SQL
- Exportação de dados do SQL Server para o Oracle com assistente de importação do SQL ServerSQL
- Tunning Index com o DTASQL