Casos do Dia a Dia – Procedures x Rollback

E aí galera,

Hoje vou falar sobre um assunto que gera muitas dúvidas quando estamos desenvolvendo códigos T-SQL: utilização de Procedures e Rollback.

Mas antes, não pode faltar aquele pequeno desafio:

“Quantas linhas serão retornadas no script abaixo?”

OBS: Pense na resposta antes de rodar o script de cada um dos exemplos desse post, se roubar toma um cascudo virtual hein xD

A) Vai executar com sucesso e irá retornar 1 linha

B) Vai executar com sucesso e irá retornar 2 linhas

C) Vai executar com sucesso e irá retornar 3 linhas

D) Vai executar com sucesso e irá retornar 4 linhas

E) Vai gerar um ERRO após o ROLLBACK e nenhuma linha será retornada

A seguir vou fazer algumas explicações e darei a resposta desse desafio. #gogogo


Desafio Inicial:

Nesse desafio, eu começo criando uma tabela e depois crio uma procedure bem simples que insere um registro com a DATA e HORA do GETDATE().

Feito isso, iniciamos a brincadeira executando a procedure uma vez. Nesse momento, temos um registro inserido na tabela (ID 1).

Nesse caso, eu NÃO utilizei o BEGIN TRAN para iniciar uma transação. Com isso, por padrão o SQL Server considera cada comando individual como uma transação e faz o COMMIT automaticamente também. Ou seja, por baixo dos panos o SQL Server faz o BEGIN TRAN / COMMIT quando nós não especificamos explicitamente.

OBS: Para mais detalhes sobre o BEGIN TRAN, consultar o link abaixo:

https://docs.microsoft.com/pt-br/sql/t-sql/language-elements/begin-transaction-transact-sql?view=sql-server-ver15

Logo, o registro ID 1 já foi inserido e comitado na tabela.

Depois eu abro uma nova transação explicitamente com o BEGIN TRAN e executo a procedure mais duas vezes. Com isso, vamos ter mais dois registros inseridos na tabela (ID 2 e 3). Contudo, logo depois eu faço um ROLLBACK que irá desfazer essas duas transações. Repare que o registro ID 1 não será desfeito, pois ele já foi inserido e comitado antes do BEGIN TRAN.

Por fim, executo a procedure mais uma vez para inserir o último registro (ID 4).

Então a RESPOSTA do desafio será:

B) Vai executar com sucesso e irá retornar 2 linhas

“Ahh Luiz, esse desafio aí foi muito fácil cara!!!”

Beleza, então vamos complicar um pouco mais =)


Mais Exemplos:

Agora vamos fazer vários outros exemplos e ir aumentando a dificuldade OK.

Primeiro, vamos criar quatro tabelas bem simples com um campo ID e outro com uma Data.

Depois vamos criar quatro procedures, sendo que elas irão executar em cascata. Segue abaixo um resumo:

  • A Procedure 1 faz um INSERT na Tabela 1 e depois executa a Procedure 2;
  • A Procedure 2 faz um INSERT na Tabela 2 e depois executa a Procedure 3;
  • A Procedure 3 faz um INSERT na Tabela 3 e depois executa a Procedure 4;
  • Por fim, a Procedure 4 faz um INSERT na Tabela 4 e termina a execução;

Exemplo 1:

Agora, vamos executar a Procedure 1 e fazer um SELECT em cada uma das quatro tabelas e conferir o resultado.

Até aqui tudo certo, todas as procedures irão executar com sucesso e inserir um registro em cada uma das tabelas.

Está muito EASY ainda, bora dificultar mais!!!

OBS: Ao final de cada um dos exemplos, vou executar um TRUNCATE TABLE para limpar cada uma das tabelas.


Exemplo 2:

Nesse segundo exemplo, vou alterar apenas a Procedure 4 e colocar uma divisão por zero para gerar um ERRO de propósito após o INSERT na Tabela 4.

Agora, eu faço as seguintes perguntas:

“Algum registro será inserido mesmo com esse erro na última procedure?“

“Ele irá desfazer algum dos INSERTs das outras procedures que já foram executadas anteriormente?”

“O registro será inserido na Tabela 4? Ou será desfeito?“

Vamos executar a Procedure 1 novamente e validar!!!

Mesmo com o erro no final, todos os registros foram inseridos nas tabelas. Como expliquei anteriormente, quando não utilizamos o BEGIN TRAN explicitamente, o SQL Server irá considerar cada um dos INSERTs como uma transação e fazer o COMMIT logo em seguida. Com isso, quando acontece o erro da divisão por zero, todos os INSERTs já foram comitados nas tabelas e não serão desfeitos.

Vamos limpar as tabelas e seguir para o próximo exemplo! #next


Exemplo 3:

Vamos alterar novamente a Procedure 4, mas dessa vez vou colocar um BEGIN TRAN no início dela. Se ela executar sem erros, no final será feito o COMMIT, caso contrário irá fazer o ROLLBACK.

“E agora, será que o registro da Tabela 4 será inserido? E os outros registros?“

Vamos executar a Procedure 1 novamente e validar!!!

Eita! Dessa vez, o registro não foi inserido na Tabela 4, pois ele estava dentro de uma transação (BEGIN TRAN) e ela foi desfeita (ROLLBACK). Com isso, tudo que foi executado após o BEGIN TRAN será desfeito!

“Caramba Luiz, acho que estou conseguindo entender agora! Que legal!”

Calma que eu ainda vou complicar um pouco mais!!! #next


Exemplo 4:

Dessa vez, vou alterar a Procedure 4 para gerar o ERRO no final, mas sem utilizar o BEGIN TRAN. Além disso, vou incluir o BEGIN TRAN na Procedure 3.

Vamos executar a Procedure 1 e conferir o resultado!

Dessa vez, a transação (BEGIN TRAN) foi aberta no início da Procedure 3. Depois, foi executado o INSERT nas Tabelas 3 e 4. Porém, como aconteceu um erro no final da Procedure 4, todas as operações que foram feitas após o BEGIN TRAN serão desfeitas. Por esse motivo, apenas as Tabelas 3 e 4 ficaram vazias.


Exemplo 5:

Acredito que nesse momento você já deve ter entendido a ideia. Então vamos para o último exemplo!

Aqui vou remover o BEGIN TRAN da Procedure 3 e colocar no início da Procedure 1.

“Bora executar o nosso último teste. Você já sabe qual será o resultado dessa vez?”

Conforme era esperado, nenhum registro foi inserido nas tabelas. No início da Procedure 1 nós abrimos uma transação (BEGIN TRAN) e tivemos um erro no final da Procedure 4. Logo, novamente todas as operações que foram feitas após o BEGIN TRAN serão desfeitas. Portanto, nesse caso TODOS os INSERTs serão desfeitos!

“TOP Luiz! Ficou muito mais fácil entender com esses exemplos cara, obrigado!!!” =)


Download – Scripts:

Segue abaixo os scripts utilizados nesse post:

https://github.com/luizvitorf/SQLServer/blob/master/Scripts/T-SQL/Casos%20do%20Dia%20a%20Dia%20-%20Procedures%20x%20Rollback.sql


Espero que tenha gostado e que isso também possa ser útil no seu dia a dia. Até o próximo post!

Me siga no LinkedIn e YouTube para ficar por dentro das novidades.

Abraço,

Luiz Vitor França Lima

Consultor SQL Server

Deixe uma resposta