Controle de transações no PDO

No último post falei sobre as funcionalidades e vantagens de se utilizar o PDO (PHP Data Object) em aplicações php e como ela torna o acesso ao banco de dados uma tarefa extremamente simples e padronizada (Clique aqui e confira o post sobre PDO).

Hoje o foco também é PDO. Veremos como fazer o controle de transações utilizando esse módulo.

Segundo a Wikipedia, “o controle de transações é um conjunto de procedimentos que é executado num banco de dados, que para o usuário é visto como uma única ação”. Em outras palavras podemos definir o controle de transações como sendo um processo do banco de dados onde mais de uma query deverá ser executada e todas elas deverão obter sucesso, caso contrário todas as outras terão suas execuções canceladas ou desfeitas.

Para ficar claro, suponha que em uma base de dados nós temos a entidade “conta” e uma outra entidade “movimentos”. Agora imagine que é em certo lugar da aplicação nós podemos lançar um movimento e que a partir das informações dessa movimentação a tabela conta sofrerá uma atualização no seu campo saldo. Até aí tudo bem. Porém é necessário ter uma garantia de que os dados da tabela movimentos foram inseridos sem problemas para que depois o saldo na tabela conta seja atualizado. Em contrapartida se na query de movimentos ocorrer tudo certo e o erro acontecer na segunda query (a da tabela conta) aí a execução de inserção em movimentos deverá ser cancelada (ou desfeita nesse caso).

Para trabalhar com controle de transações devemos levar em consideração que o SGBD deve estar apto à essa funcionalidade. Os mais famosos bancos de dados existentes têm suporte ao controle de transações.

Para implementar um controle de transações de forma correta você precisa entender um pouco mais os 3 comandos a seguir:

– Begin Transaction: comando para indicar onde uma transação será iniciada. A partir desse comando, todas as querys surtirão efeitos permanentes no banco de dados somente quando for executado o commit;

– Commit: comando para confirmar a execução de todas as querys executadas na transação. Após o commit não poderá ser desfeito as manipulações ocorridas. O commit deve ser executado depois de todas as verificações de erros.

– Rollback: comando para desfazer a ação todas as querys que foram executadas na transação. É utilizado sempre que algum erro ocorre.

Vamos a um exemplo prático agora da utilização de transações no PDO. Para isso utilizaremos a analogia dos movimentos e conta descritos anteriormente.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
$pdo = new PDO("mysql:host=localhost;dbname=nomeDoBanco", "root", "suaSenha");
if(!$pdo){
    die('Erro ao iniciar a conexão');
}
 
$pdo->beginTransaction();/* Inicia a transação */
$movimento = $pdo->query("INSERT INTO movimentos(idmovimento, data, valor, tipo, idconta) VALUES (1, '2011-12-08', 100, 'entrada', 1)");
 
if(!$movimento){
    die('Erro ao lancar movimento'); /*É disparado em caso de erro na inserção de movimento*/
}
 
$atualiza_saldo = $pdo->query("UPDATE conta SET saldo = saldo + 100 WHERE idconta = 1");
 
if(!$atualiza_saldo){
    $pdo->rollBack(); /* Desfaz a inserção na tabela de movimentos em caso de erro na query da tabela conta */
    die('Erro ao atualizar saldo');
}
 
$pdo->commit(); /* Se não houve erro nas querys, confirma os dados no banco */
echo 'Lançamento efetuado com sucesso!';

Repare que antes de qualquer query eu chamo o método beginTransaction() do objeto $pdo. Feito isso a minha transação está iniciada. Agora insiro os dados na tabela movimento, informando o id da movimentação, a data, o valor, o tipo e a qual conta esse movimento está associado.

Se der erro, uma mensagem será disparada e a aplicação “morre”. Caso contrário ele parte para a segunda query, que é a atualização do saldo na tabela conta que referenciou a movimentação. Se essa query falhar por algum motivo, o comando rollback() é utlizado para que a inserção na tabela de movimentos seja desfeita (cancelada). Se não ocorrer erros o commit() é executado, os dados das duas tabelas são confirmados permanentemente no banco de dados e a transação é finalizada.

Espero que esse post lhes sejam útil.

Até a próxima.

Abs

Siga-me no twitter: @rafaelwendel

É formado em Sistemas de Informação, pós-graduado em Sistemas de Banco de Dados e mestre em Educação com foco em Tecnologias Sociocomunitárias. Trabalha como professor de ensino técnico e tecnológico no Instituto Federal de Educação, Ciência e Tecnologia de São Paulo ministrando disciplinas nas áreas de programação, banco de dados, desenvolvimento de projetos e engenharia de software.

Posts relacionados

Comentários

  1. Show de bola mano! Agora me tira uma duvida please! Para que funcine eu preciso sempre usar o metodo DIE para constatar o erro ? E o rollback porq não foi usado no INSERT?

    Grato pela força Rafael!

  2. Olá,
    Parabéns pelo codigo muito interressante, tenho uma duvida a onde tu disse na explicação que a ‘aplicação “morre”’, isto é feito pelo o comando die.
    at+

  3. Na antiga biblioteca do mySQL para PHP (mysql_*), era necessário configurar o AUTOCOMMIT = 0 antes de usar o BeginTransaction. No PDO isso já é automático?

  4. Será que posso usar uma estrutura assim?
    Try{
    $conexao->beginTransaction();
    //Inserindo Primeiro Registro
    if(insert){
    //registro inserido
    }else{
    //erro ao inserir registro
    throw new Exception(‘Erro ao inserir!’);
    }
    //Inserindo Segundo Registro
    if(insert2){
    //registro inserido
    }else{
    //erro ao inserir registro
    throw new Exception(‘Erro ao inserir!’);
    }
    $conexao->commit();
    } catch (Exception $exc) {
    $conexao->rollBack();
    }

    Usando exceções, minha dúvida é se quando eu dou um throw new Exception mata a aplicação e cai no catch

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *