Demétrio's profileDemétrio Silva - Sql Ser...BlogListsNetworkMore ![]() | Help |
|
|
September 08 Situações onde o bloco catch não é executadoGalera,
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 Comments (1)
TrackbacksThe trackback URL for this entry is: http://demetriosqlserver.spaces.live.com/blog/cns!1D50CF1AC3A02CDE!270.trak Weblogs that reference this entry
|
|
|