Transações George Azevedo da Silva José Antônio da Cunha O que é Transação? É uma unidade lógica de processamento que tem por objetivo preservar a integridade e a consistência dos dados de um sistema. ContaCorrente Débito retirar ContaAplicação Crédito Este requerimento de “ou faz tudo ou não faz nada” é chamado de atomicidade. Transações Para que você realize esta unidade de processamento com atomicidade, você deve abrir a transação, realizar as operações com dados, verificar se algum problema ocorreu. Se todas as operações com dados tiverem sido realizadas com sucesso, você deve confirmar a operação. Caso algum problema tenha ocorrido, você deve garantir que nada seja feito. Observe o esquema em seguida: Criar a unidade de processamento realizar o DÉBITO checar a ocorrência de erro se ocorreu algum erro: 1 – desfaça qualquer operação que tenha sido feita até este ponto. 2 – interrompa o processamento aqui. Realizar CRÉDITO checar a ocorrência de algum erro. se ocorreu erro 1 – Desfaça qualquer operação que tenha sido feita até este ponto. 2 – interrompa o processamento aqui. Se não ocorrer nenhum problema Confirme a operação Transação Para realizar o processamento anterior, você precisa utilizar três comandos: 1. 2. 3. Begin Transaction – cria uma transação, ou seja, cria uma unidade de processamento lógico; Roolback Transaction – encerra a transação e desfaz qualquer operação que tenha sido realizada com dados; Commit Transaction – encerra a transação e efetiva qualquer operação que tenha sido realizada com dados. Observe agora o esquema seguinte: BEGIN TRANSACTION realizar o débito checar a ocorrência de erro se ocorreu algum erro: 1 – ROLLBACK TRANSACTION 2 – RETURN Realizar CRÉDITO checar a ocorrência de algum erro. se ocorreu erro 1 – ROLLBACK TRANSACTION 2 – RETURN Se não ocorrer nenhum problema COMMIT TRANSACTION @@ERROR É uma variável global (função) “alimentada” pelo próprio SQL Server após a realização de qualquer comando da linguagem Transact_SQL. Se não ocorrer erro @@ERROR = 0 Caso ocorra erro @@ERROR = n• erro (existente na tabela sysmessages) @@ERROR Sendo assim é com a variável @@ERROR que você verifica a ocorrência de erros durante o processamento dos seus dados. Observe o seguinte esquema: @@ERROR BEGIN TRANSACTION Realizar o DÉBITO IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RETURN END Realizar o CRÉDITO IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RETURN END COMMIT TRANSACTION RAISERROR() Você pode usar função RAISERROR() para enviar uma mensagem em português mais significativa para a aplicação. Exec sp_addmessage 50001, 16, ‘ocorreu um erro de processamento na operação %s ‘ Exec sp_addmessage 50002, 16, ‘conta não encontrada na operação %s ‘ Tabela sysmessages RAISERROR() BEGIN TRANSACTION Realizar o DÉBITO IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RAISERROR(50001, 16, 1, ‘DÉBITO’) RETURN END Realizar o CRÉDITO IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RAISERROR(50001, 16, 1, ‘CRÉDITO’) RETURN END COMMIT TRANSACTION Criando a Tabela ContaSaldo Tabela Conta Saldo Conta Saldo 1 1000 2 1500 Comando de Transferência create proc sp_Transferencia @valor float, @ContaDeb int, @contaCred int AS declare @aROWCOUNT int BEGIN TRANSACTION -- Realiza Debito Update ContaSaldo Set Saldo = Saldo - @valor Where Conta = @ContaDeb IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RAISERROR(50001, 16, 1, 'DÉBITO') RETURN END Comando de Transferência -- Realiza Credito Update ContaSaldo Set Saldo = Saldo + @valor Where Conta = @ContaCred set @aROWCOUNT = @@ROWCOUNT IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION RAISERROR(50001, 16, 1, 'CRÉDITO') RETURN END IF @aROWCOUNT = 0 BEGIN ROLLBACK TRANSACTION RAISERROR(50002, 16, 1, 'CRÉDITO') RETURN END COMMIT TRANSACTION Comando de Transferência -- Realiza a transferência de 100 reais da conta 1 para a 2 exec sp_Transferencia 100, 1, 2 -- Realiza a transferência de 50 reais da conta 1 para a 3 exec sp_Transferencia 50, 1, 3 -- Este segundo comando reporta a mensagem de erro Transação Implícita e Explícita A transação que é iniciada com BEGIN TRANSACTON e encerrada com COMMIT ou ROLLBACK TRANSACTION é chamada de transação explícita. Se você executar um comando DML (INSERT, UPDATE OU DELETE) avulso, ou seja, fora de um BEGIN ou COMMIT TRANSACTION, o SQL Server trata cada um desses comandos como uma transação, ou seja, uma transação implícita. Nesse caso a atomicidade é mantida para cada comando individual. Transação Implícita e Explícita Se você quiser, pode configurar a sua sessão para trabalhar no modo “transação implícita”. Para tanto, basta executar o seguinte código: SET IMPLICIT_TRANSACTIONS ON ALTER TABLE REVOKE INSERT CREATE DROP TRANCATE TABLE UPDATE SET IMPLICIT_TRANSACTIONS OF GRANT SELECT DELETE O processamento de uma Transação 1. 2. 3. 4. 5. 6. Quando uma transação inicia, ela é registrada no Transaction log. Assim que ela termina, o SQL Server registra no log o COMMIT ou o ROLLBACK. O processo de CHECKPOINT efetiva as transações com COMMIT e registra no log que a respectiva já foi efetivada. O processo que limpa o log retira desse arquivo as transações que já foram efetivadas pelo CHECKPOINT e as transações com ROLLBACK. Se o sistema for interrompido propositadamente ou não, ao ser reiniciado, o processo chamado RECOVER entra em ação. Ele efetiva as transações que estavam com COMMIT, mas que ainda não haviam sido efetivadas, e desfaz qualquer transação que porventura tenha sido processada pela metade devido à interrupção do sistema. O próximo processo que limpa o log retira desse arquivo as transações que já foram efetivadas pelo CHECKPOINT ou pelo RECOVERY e as transações com ROLLBACK, liberando espaço nesse arquivo. Transação Aninhada Uma transação pode ser aberta dentro de outra transação. A variável global @@TRANCOUNT contém um número que indica quantas transações estão abertas em sua sessão. Veja o exemplo a seguir: SELECT @@TRANCOUNT /* é igual a 0 */ BEGIN TRANSACTION primeira INSERT INTO Teste_Um values (3) IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION /*Desfaz a primeira transação*/ RAISERROR(‘Erro da primeira transação’,16,1) RETURN END BEGIN TRANSACTION segunda INSERT INTO Teste_Dois values (‘C’) IF @@ERROR <> 0 BEGIN ROLLBACK TRANSACTION /*Desfaz a segunda transação*/ RAISERROR(‘Erro da segunda transação’,16,1) RETURN END SELECT @@TRANCOUNT /* A variável @@TRANCOUNT vale 2 */ COMMIT TRANSACTION segunda SELECT @@TRANCOUNT /* A variável @@TRANCOUNT vale 1 */ COMMIT TRANSACTION primeira SELECT @@TRANCOUNT /* A variável @@TRANCOUNT vale 0 */ A marca de Save Point Para que você possa confirmar parcialmente uma transação, basta que você atribua um nome a ela. Para que você desfaça uma transação parcialmente, terá que utilizar marcas de “save Point” e desfazer a transação até esta marca: BEGIN TRANSACTION INSERT INTO Teste_Um values (1) SAVE TRANSACTION Ponto_A /* Esta operação é confirmada */ /* marca de SAVE POINT */ INSERT INTO Teste_Dois values (‘A’) SELECT * FROM Teste_Um SELECT * FROM Teste_Dois ROLLBACK TRANSACTION Ponto_A desfeito */ /*Apenas INSERT Teste_Dois é COMMIT TRANSACTION /* Confirma as operações que não foram desfeitas */ Sintaxe BEGIN TRAN [SACTION] [ <Nome_Transação>) | @variável ] . COMMIT TRAN [SACTION] [ <Nome_Transação>) | @variável ] . COMMIT [ WORK ] . ROLLBACK TRAN [SACTION] [[ <Nome_Transação>) | @variável | NomeSavePoint | @variável_SavePoint ] . ROLLBACK [ WORK ] . SAVE TRAN [ SACTION ] ( Nome_savapoint) | @variável_savepoint)