TRANSAÇÕES 1. Introdução Transação Uma transação é uma unidade lógica de trabalho (processamento), formada por um conjunto de comando SQL, que tem por objetivo preservar a integridade e a consistência dos dados. Ao final de uma transação, ou se tem todos os seus dados íntegros e consistentes no banco ou eles retornam ao estado anterior ao início da transação (ou se tem os dados consistentes ou não se tem nada). Exemplo: Uma operação cuja finalidade é transferir uma quantia de R$100 da conta 123 para a conta 456, presumivelmente, deveria ser uma operação indivisível – “transferir dinheiro de uma conta para outra” – entretanto, estão envolvidas duas operações (atualizações) separadas no banco de dados. UPDATE CONTA 123 SET SALDO = SALDO – 100; UPDATE CONTA 456 SET SALDO = SALDO + 100; Considerando que estes comandos fazem parte de uma TRANSAÇÃO (veremos como indicar isso): - Se o primeiro comando falhar, o segundo não poderá ser executado; - Se o segundo falhar, o primeiro não poderá ser confirmado (será “desfeito”). Assim, os comandos em uma transação são ditos atômicos no que diz respeito à sua execução e à recuperação do banco de dados: • Se uma transação for concluída com sucesso, as alterações por ela realizadas serão confirmadas e não poderão ser desfeitas. • Se uma transação é concluída com fracasso, o SGBD deve desfazer todas as operações de atualização de dados contidas na transação em questão. Pág. 1 2. TRANSAÇÃO (principais comandos) 2.1. Iniciando uma transação explícita Padrão SQL: START TRANSACTION [NÍVEL DE ISOLAMENTO] SQL Server: BEGIN TRANSACTION [NÍVEL DE ISOLAMENTO] 2.2. Concluindo uma transação Com sucesso: COMMIT [WORK] Com fracasso: ROLLBACK [WORK] Desfaz todas as ações ocorridas durante a transação. 2.3. Exemplos práticos: a) Digite ou copie e execute no SQL Server (o BD deve ser criado isoladamente): CREATE DATABASE DBBANCO ON PRIMARY (NAME=DBTESTE, FILENAME="D:\BANCOS\DBTESTE.MDF", SIZE=10MB); CREATE TABLE DBBANCO.DBO.TBCONTA ( CODIGO INT NOT NULL IDENTITY PRIMARY KEY, CONTA INT NOT NULL, SALDO INT NOT NULL, LIMITE INT NOT NULL); Com a tabela TBCONTA criada, vamos aos exemplos práticos de transação: b) Exemplo 1 (digite ou copie e execute no SQL Server): BEGIN TRANSACTION INSERT INTO DBBANCO.DBO.TBCONTA (CONTA,SALDO,LIMITE) VALUES (123,5000,10000) INSERT INTO DBBANCO.DBO.TBCONTA (CONTA,SALDO,LIMITE) VALUES (456,200,NULL) IF @@ERROR<>0 ROLLBACK ELSE COMMIT O SGDB dará uma mensagem informando o sucesso no primeiro insert e a falha no segundo insert: (1 row(s) affected) Não é possível inserir o valor NULL na coluna 'LIMITE', tabela 'DBBANCO.dbo.TBCONTA'; a coluna não permite nulos. Falha em INSERT. A instrução foi finalizada. Pág. 2 c) Digite ou copie e execute o seguinte comando: SELECT * FROM DBBANCO.DBO.TBCONTA Observe pelo resultado do comando que a tabela TBCONTA continua vazia (não há linhas). Isso ocorreu apesar do primeiro insert ter sido inicialmente concluído com sucesso. Como os dois comandos insert fazem parte de uma transação, a falha no segundo insert fez com que o código de erro (@@erro) fosse diferente de 0, e o comando ROLLBACK foi executado (as duas operações de insert foram revertidas). Caso não ocorresse erro algum (@@erro = 0) o comando COMMIT seria executado e as operações confirmadas na base de dados. d) Digite ou copie e execute o seguinte comando (AGORA AS LINHAS SERÃO INCLUÍDAS NORMALMENTE): BEGIN TRANSACTION INSERT INTO DBBANCO.DBO.TBCONTA (CONTA,SALDO,LIMITE) VALUES (123,5000,10000) INSERT INTO DBBANCO.DBO.TBCONTA (CONTA,SALDO,LIMITE) VALUES (456,200,400) IF @@ERROR<>0 ROLLBACK ELSE COMMIT Pág. 3 Exemplo 2 (digite ou copie e execute no SQL Server): a) Digite ou copie e execute no SQL Server: BEGIN TRANSACTION UPDATE DBBANCO.DBO.TBCONTA SET SALDO = SALDO - 1000 WHERE CONTA=123 UPDATE DBBANCO.DBO.TBCONTA SET SALDO = SALDO + 100000000000 WHERE CONTA=456 IF @@ERROR<>0 ROLLBACK ELSE COMMIT Observe a mensagem de erro apresentada: (1 row(s) affected) Msg 8115, Level 16, State 2, Line 3 Erro de estouro aritmético ao converter expression no tipo de dados int. A instrução foi finalizada. b) Digite ou copie e execute o seguinte comando: SELECT * FROM DBBANCO.DBO.TBCONTA Observe pelo resultado do comando que NÃO houve alteração nos saldos das DUAS contas (conta 123 e conta 456). Pág. 4 Exemplo 3 (digite ou copie e execute no SQL Server): a) EXCLUA AS DUAS LINHAS DA TABELA TBCONTA b) Digite ou copie e execute no SQL Server: BEGIN TRANSACTION INSERT INTO DBBANCO.DBO.TBCONTA (CONTA,SALDO,LIMITE) VALUES (123,5000,10000) INSERT INTO DBBANCO.DBO.TBCONTA (CONTA,SALDO,LIMITE) VALUES (456,200,400) UPDATE DBBANCO.DBO.TBCONTA SET SALDO = SALDO - 1000 WHERE CONTA=123 UPDATE DBBANCO.DBO.TBCONTA SET SALDO = SALDO + 100000000000 WHERE CONTA=456 IF @@ERROR<>0 ROLLBACK ELSE COMMIT O SGBD apresentará a seguinte mensagem: (1 row(s) affected) (1 row(s) affected) (1 row(s) affected) Msg 8115, Level 16, State 2, Line 5 Erro de estouro aritmético ao converter expression no tipo de dados int. A instrução foi finalizada. EXERCÍCIOS: c) O que acontecerá no BD (tabela TBCONTA)? d) Experimente excluir todos os registros (se houver) e executar os comandos abaixo, fora da transação. O que ocorreu? INSERT INSERT UPDATE UPDATE INTO DBBANCO.DBO.TBCONTA (CONTA,SALDO,LIMITE) VALUES (123,5000,10000) INTO DBBANCO.DBO.TBCONTA (CONTA,SALDO,LIMITE) VALUES (456,200,400) DBBANCO.DBO.TBCONTA SET SALDO = SALDO - 1000 WHERE CONTA=123 DBBANCO.DBO.TBCONTA SET SALDO = SALDO + 100000000000 WHERE CONTA=456 Pág. 5