Advanced Series – Stored Procedures Parte 2 (Transações) Neste artigo, daremos continuidade aos procedimentos armazenados, ampliando os recursos que foram abordados na Parte 1 desta série de artigos. Neste artigo, daremos continuidade aos procedimentos armazenados, ampliando os recursos que foram abordados na Parte 1 desta série de artigos. Vamos enriquecer os conceitos a cada passo, passando pelo conceito de transação e os atributos em conformidade com as propriedades ACID, como o MySQL garante essa conformidade, o modo AUTOCOMMIT e exemplos que exibem a sintaxe utilizada para produzir os recursos abordados. Serão apresentadas as principais estruturas para iniciar e finalizar transações e como utilizarmos de SAVEPOINT. Após este artigo, você será capaz de: · Definir o que é uma transação e quais as suas vantagens; · Definir o que é COMMIT e ROLLBACK e quais são as suas funções; · Definir o que é o modelo ACID; · Explicar como o MySQL dá suporte ao modelo ACID; · Definir e utilizar AUTOCOMMIT; · Iniciar e finalizar uma transação no MySQL; · Definir e utilizar SAVEPOINT; Introdução – Transação Sabemos que grande parte dos vários processos existentes no mundo real, como transferências de valores em instituições bancárias, DOC’s, compras em comércio eletrônico e outros serviços utilizam transações que são um atributo ou artifício comum em bancos de dados comerciais. Muitos conceitos surgiram desde que Edgard Frank Codd, ou simplesmente Ted, divulgou as Leis do Modelo Relacional e criou este modelo. Tais leis eram para serem seguidas à risca para que um SGBD realmente contemplasse tal modelo, mas, alguns destes relaxam nas implementações para garantir mais performance. Alguns autores como C. J. Date que é a principal referência após a morte de Codd, deram continuidade ao trabalho e defende o conceito de transação da seguinte forma: “Transação é uma unidade lógica de trabalho, envolvendo diversas operações de bancos dados.” (C. J. Date – Introdução a Sistemas de Bancos de Dados – página 63) Há ainda quem diga que uma transação é “todo e qualquer comando que altera o estado do banco de dados”, mas de acordo com o que defende Codd e C. J. Date, este conceito não está completo e veremos mais à frente o por quê. Ainda, o usuário deve ser capaz de informar ao sistema quando operações distintas fazem parte de uma transação. Basicamente, esta começa quando uma operação BEGIN é executada, e termina quando uma operação COMMIT ou ROLLBACK correspondente é executada. Desta forma, podemos perceber que uma transação logo é formada caracteristicamente por estes comandos. Podemos consistir o conceito de transação com um exemplo clássico que é utilizado quando precisamos iniciar este assunto em sala de aula, que é uma explicação análoga a uma transferência bancária. Em meio a um processo de transferência de valor entre contas, temos alguns comandos SQL que são executados todos de uma vez, formando a tal unidade lógica, que por sua vez, envolve diversas operações de bancos de dados, tais como INSERT e UPDATE. Transações também podem conter DELETE e SELECT, mas no caso da transferência, utilizaremos somente o UPDATE. Digamos que nossa agência tenha dois correntistas, A e B e num belo dia, A resolve fazer uma transferência de R$ 50,00 para B. Esta transação será feita pela internet, através de um sistema de internet banking, então, A acessará a sua conta e completará a operação. Do lado servidor, o banco de dados recebe o valor e a conta de destino, tal valor é subtraído da conta de origem e adicionado na conta de destino. Nesse momento há uma conferência por parte do SGBD – “tudo correu bem” – então a transação é finalizada com sucesso. Vamos esboçar o procedimento. Figura 01. Transferência de valor entre contas. Como o procedimento da Figura 01? Na linha 1, trocamos o delimitador para utilizarmos o “;” em meio ao procedimento, na linha 2, começamos a definição do procedimento com o comando CREATE PROCEDURE, seguido pelo seu nome e os parâmetros, que são respectivamente a origem do valor, o destino do valor e o valor monetário. Na linha 3, utilizamos o comando BEGIN para delimitar os comandos de nosso procedimento. Nas linhas 4 e 5, temos os comandos UPDATE que subtrai o valor monetário da conta de origem e o soma a conta de destino. COMMIT e ROLLBACK Neste básico exemplo, não utilizamos COMMIT e ROLLBACK mas já dá para entendermos o que é uma transação. Em um exemplo mais à frente, veremos que o COMMIT é uma operação de confirmação de que correu tudo bem e que todos os comandos que fazem parte da unidade lógica, ou do procediemtno armazenado, forma executados com sucesso e o banco de dados encontra-se em um estado consistente. O ROLLBACK retornará todos os comandos anteriores àquele onde houve um erro, ou seja, tudo será desfeito se houve um problema com algum comando dentro de uma transação. Para melhor entendermos tal situação de ROLLBACK que é também chamada por Date de “recuperação do estado consistente”, usemos novamente nosso exemplo e imagine se caso o primeiro comando seja executado, mas na hora de creditar o valor na conta B houvesse um erro, para onde iria o dinheiro? Perdeu? Como é? Isso não poderia acontecer de maneira nenhuma. Nesse caso, o SGBD se encarregaria de fazer o ROLLBACK dos comandos anteriores ao erro retornando o banco de dados para o momento de antes, devolveria na verdade o valor para A, mantendo intacta sua quantia de saldo imediatamente anterior ao início da transação. Sendo assim, vamos aos conceitos: COMMIT: indica o término de uma transação bem-sucedida. Ela informa ao gerenciador de transações que uma unidade lógica de trabalho foi concluída com sucesso, o banco de dados já está novamente em um estado consistente e todas as atualizações feitas por essa unidade de trabalho já podem se tornar permanentes. ROLLBACK: assinala o término de uma transação malsucedida. Ela informa ao gerenciador de transações que algo saiu errado, que o banco de dados pode estar em um estado inconsistente, e que todas as atualizações feitas pela unidade lógica de trabalho até agora devem ser desfeitas. As vantagens do uso de transações em um ambiente web por exemplo, são inúmeras. As principais são: Não carregar com processamento no lado cliente; Ter uma estrutura modular; Evitar perda de informações, pois um usuário pode simplesmente fechar o browser enquanto e apagar todo o carrinho de compras; Diminuir o tráfego na rede já que estaremos trafegando parâmetros e os entregando ao banco de dados; Ter controle sobre os erros que possam acontecer com as lógicas de definição de fluxo de dados; Controle de atualizações de registros através de bloqueios. Propriedades ACID Para que haja toda essa engenharia, devemos ainda conhecer as propriedades ACID, que são atributos que toda transação precisa ter para que não existam problemas durante a execução. Não aprofundaremos muito em tais propriedades pois esse tema daria um novo artigo, mas, o ACID é uma sigla que significa justamente: Atomicidade: toda transação deverá ser atômica, o verdadeiro “tudo ou nada”; Consistência: as transações devem preservar a consistência do banco de dados, ou seja, transforma um estado consistente do banco de dados em outro estado consistente, sem necessariamente preservar o estado de consistência em todos os pontos intermediários. Isolamento: as transações são isoladas umas das outras, de acordo com o nível de isolamento definido no momento em que a transação se inicia, que no MySQL são: REPEATABLE READ, READ COMMITED, READ UNCOMMITED e SERIALIZABLE. (Figura 02.) Figura 02. Nível de isolamento padrão definido no MySQL. · Durabilidade: uma vez comprometida uma transação, suas atualizações sobrevivem no banco de dados mesmo que haja uma queda subseqüente do sistema. Suporte do MySQL às Propriedades ACID O MySQL dá 100% de suporte às propriedades ACID com a Engenharia de Armazenamento INNODB da INNOBASE Oy, que é a Engenharia ou Engine mais comumente utilizada para se trabalhar com um ambiente seguro, como possibilidade de Auto Recovery que é a recuperação do banco de dados após uma falha e amparo com vários arquivos de log. Para maiores informações sobre o INNODB, consulte o site da INNOBASE Oy. O suporte para este atributo é provido pela MySQL AB. AUTOCOMMIT Normalmente, em SGBD’s como o SQL Server e o MySQL, gerenciadores com os quais tenho mais experiência, temos transações implícitas que são estreladas pelos comandos SELECT, INSERT, UPDATE e DELETE, ou seja, comandos DML e transações explícitas que podem ser iniciadas por um BEGIN e finalizadas por um END. As transações implícitas são aquelas que têm um COMMIT interno e já tornam quaisquer modificações nos dados permanentes no(s) arquivo(s) de dados em disco. Transações explícitas são aquelas que têm um início e fim explicitado pelo desenvolvedor. O MySQL utiliza o modo chamado AUTOCOMMIT para controlar a efetividade da modificação de dados das transações no banco de dados, ou seja, se AUTOCOMMIT = 1, as transações implícitas sempre terão um COMMIT interno, enquanto que, se AUTOCOMMIT = 0, o SGBD esperará por um COMMIT explícito para tornar permanente as últimas manipulações nos dados. Vejamos como funciona o AUTOCOMMIT num comparativo. A Figura 03 tratará de uma transação implícita com o modo AUTOCOMMIT = 1, em seguida faremos um teste com o modo AUTOCOMMIT = 0, já na Figura 04. Figura 03. Com AUTOCOMMIT = 1, instruções DML recebem um COMMIT interno e se tornam permanentes em disco. Figura 04. Com AUTOCOMMIT = 0, qualquer manipulação nos dados aguarda por um COMMIT ou ROLLBACK. Trabalhando com Transações no MySQL Para trabalharmos com transações no MySQL, podemos iniciá-las explicitamente ou dentro de um procedimento armazenado, o qual é o foco deste artigo. Como uma transação é delimitada por um BEGIN [...] END, podemos utilizar os seguintes comandos para iniciarmos uma transação: BEGIN (o mais comum); BEGIN WORK; START TRANSACTION; Pegando embalo novamente na transferência bancária, podemos melhorar o procedimento anterior, adicionando mais semântica ao mesmo. Já sabemos como implementar estruturas condicionais dentro dos procedimentos que é o famoso IFTHEN-ELSE e veremos no próximo exemplo como aninhar os blocos de início e fim da transação. Basicamente, faremos a conferência dos parâmetros enviados para o procedimento, após a conferência entramos na lógica que manipulará os valores na transação de transferência que ao completar a execução dos comandos parte da unidade lógica, envia um COMMIT para efetivar os dados da memória para o arquivo de dados e caso os valores não forem informados, o processamento cairá no ELSE e a transação será restaurada com o ROLLBACK. Na verdade, esse procedimento ainda não tem o conceito totalmente coberto do que realmente é uma transação, mas, como um dia eu escutei de um amigo, “vamos com calma, dividir e conquistar”. A Figura 05 traz a nova versão do procedimento armazenado. Figura 05. Utilizando condicional, COMMIT e ROLLBACK. Ao executarmos o procedimento na própria linha de comando, passando os parâmetros de forma equivocada, a mensagem de erro será disparada e o ROLLBACK acontecerá, como mostra a Figura 06. Figura 06. Informando parâmetros inconsistentes do ponto de vista da lógica do procedimento com “user variables”. Utilizamos na chamada do procedimento, um recurso que pode ser criado per connection, ou seja, são variáveis do usuário, amarradas à conexão do usuário que recebem um valor através da declaração SET. Depois de atribuídos os valores, estes são passados como parâmetro para o procediemtno armazenado. Como usamos && que é um sinônimo de AND na condição, @v_val é igual a 0 e não maior que 0, então o erro foi retornado, caindo no ELSE e executando o ROLLBACK. SAVEPOINT A partir do MySQL 4.0.14 e 4.1.1. o INNODB suporta os comando SQL SAVEPOINT e ROLLBACK TO SAVEPOINT. Esse recurso nos permites criar “pontos de salvamento” em meio a uma transação, possibiltando que esta seja recuperada até determinado ponto. Pode ser feito em transações implícitas e em meio a uma transação explícita, dentro de procedimentos, independente do valor de AUTOCOMMIT. Obrigatoriamente, um SAVEPOINT será vinculado a uma transação, caso um novo ponto seja adicionado fora de um BEGIN [...] END, ao retornar para este com um ROLLBACK TO SAVEPOINT name, um erro será enviado salientando a inexistência do ponto de salvamento referenciado, como mostra a Figura 07. Figura 07. Criando um ponto de salvamento, um SAVEPOINT fora de instruções BEGIN [...] END. A Figura 08 mostra a criação de um ponto de salvamento e ao retorno ao momento anterior após algumas inserções de dados. Conclusão Concluímos então mais uma parte do nosso estudos sobre os procedimentos armazenados ou stored routines no MySQL e agora, já temos ciência de como funciona uma transação, com vários atributos para controle interno como os pontos de salvamento, COMMIT e ROLLBACK, além de termos visto os conceitos de das propriedades ACID. No próximo artigo da série, trabalharemos com mais prática envolvendo as transações, níveis de isolamento e tratamento de erros. Referência Bibliográfica Manual MySQL 5.0 - http://dev.mysql.com/doc/refman/5.0/en/; · Dubois, Paul/Stefan, Hinz/Pedersen, Carsten – MySQL 5.0 Certification Guide – MySQL Press; · Date, C. J. – Introdução a Sistemas de Bancos de Dados – American Edition – Editora Campus; Leia mais em: http://www.devmedia.com.br/advanced-series-stored-procedures-parte-2transacoes/7445