Você tem noção da importância das transactions?

Olá, tudo bem?

Hoje vou falar sobre um assunto que dificilmente é abordado sobre CodeIgniter, as Transactions, ou transações para os íntimos.

Se você não sabe o que são as transactions, dê uma pesquisada no Google apenas para se familiarizar com elas, mas de qualquer modo aqui vai um pequeno resumo.

Basicamente as transactions garantem que uma querie ou um grupo de queries executem suas tarefas com sucesso até o final, ou caso contrário, todo o processo é desfeito, ou seja, se tudo ocorreu bem, dá um commit no banco, caso não, dá um rollback.

E pra que vou usar isso no CodeIgniter?

Vamos a um exemplo clássico:

Vamos imaginar que você tenha uma tabela chamada clientes e uma tabela chamada telefones.

O campo ID da tabela clientes é sua chave primária e chave estrangeira da tabela telefones, ou seja, é o campo que vai fazer o relacionamento entre as duas tabelas.

Algo parecido com isso:

Tabela Clientes
id
nome
sobrenome

Tabela Telefones
id
id_cliente
telefone

Quando você está na tela de cadastro do cliente você irá precisar incluir um ou mais telefones para aquele cliente, certo? Mas como inserir um registro na tabela telefones se você ainda não tem o id_cliente, já que este ainda não foi salvo?

Existem outras maneiras de resolver isto, mas hoje vou focar somente no exemplo mais simples que usa os transactions.

A solução para isto seria usar uma função nativa do MySQL chamada insert_id, que retornar o último id inserido imediatamente após a inserção dos dados no banco.

Ou seja, o fluxo seria assim:

  1. Salvo os dados do cliente no banco.
  2. Recupero o id desta inserção através da função $this->db->insert_id()
  3. Pego este id e agora salvo o telefone deste cliente na tabela telefones, pois agora tenho todos os valores dos campos.

Até aí tudo bem, mas você deve ter notado que se você está rodando um sistema com muitos acessos simultâneos, pode ocorrer de que a função insert_id acabe recuperando o id de uma outra inserção, bagunçando totalmente o relacionamento das duas tabelas.

É aí que entram as transactions.

Quando você habilita as transactions antes de iniciar a inserção dos dados, é como se elas empacotassem todo o código que insere os dados no banco para garantir que o registro a ser inserido será aquele mesmo, e não de outra inserção.

Caso ocorra algum erro no meio do processo, as transactions detectam isto e desfazem toda a operação, garantindo assim uma integridade nos seus dados.

Veja abaixo como utilizar as transactions.

Rodando Transactions

Para rodar as suas queries usando transactions você irá usar o comando: $this->db->trans_start() e $this->db->trans_complete() como segue no exemplo:

$this->db->trans_start();
$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->query('AND YET ANOTHER QUERY...');
$this->db->trans_complete();

Você pode rodar quantas queries desejar entre as funções start e complete que elas irão ser “comitadas” ou “rolled back” em caso de sucesso ou falha como para qualquer tipo de query.

Strict Mode

Por padrão o CodeIgniter roda todas as transações em Strict Mode. Quando Strict Mode está habilitado, se você rodar múltiplos grupos de transações, se um grupo falhar, todos os outros serão desfeitos “rolled back“.

Se o Strict Mode estiver desabilitado, cada grupo é tratado de modo independente, o que significa que se um grupo falhar, isso não irá interferir nos outros.

O Strict mode pode ser desabilitado usando a linha abaixo:

$this->db->trans_strict(FALSE);

Lidando com os Erros

Se você tiver com a opção de error reporting habilitada nas configurações do seu banco de dados, em config/database.php você irá ver uma mensagem de erro padrão se não foi possível fazer o commit.

Se o modo debugging estiver desabilitado, você poderá gerenciar seus erros desta maneira:

$this->db->trans_start();
$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->trans_complete();

if ($this->db->trans_status() === FALSE)
{
        // generate an error... or use the log_message() function to log your error
}

Habilitando as Transactions

As transactions são habilitadas automaticamente quando você usa $this->db->trans_start(). Se você quiser desabilitar as transactions você pode fazer isso usando $this->db->trans_off():

$this->db->trans_off();

$this->db->trans_start();
$this->db->query('AN SQL QUERY...');
$this->db->trans_complete();

Quando as transactions estão desabilitadas, suas queries serão “auto-commitadas”, exatamente como se você estivesse rodando queries sem as transactions.

Modo de Teste

Você poderá, opcionalmente, colocar o sistema de transactions em “modo teste”, o que fará com que suas queries não sejam “commitadas“, mesmo se as queries produzirem um resultado válido.

Para usar o modo teste, simplesmente passe o primeiro parâmetro como TRUE na função, assim:

$this->db->trans_start(TRUE); // Query será rolled back
$this->db->query('AN SQL QUERY...');
$this->db->trans_complete();

Rodando Transactions Manualmente

Se você quiser de rodar transactions manualmente você poderá fazer assim:

$this->db->trans_begin();

$this->db->query('AN SQL QUERY...');
$this->db->query('ANOTHER QUERY...');
$this->db->query('AND YET ANOTHER QUERY...');

if ($this->db->trans_status() === FALSE)
{
        $this->db->trans_rollback();
}
else
{
        $this->db->trans_commit();
}

Nota: certifique-se de usar $this->db->trans_begin() quando rodar transactions manualmente e NÃO $this->db->trans_start().

É isso, espero que a dica tenha sido útil.

Abraços

Fábio

Fábio S. Reszko

Sou Programador PHP desde 2006 e eu acredito sinceramente que programar usando um Framework PHP é a solução para os problemas de códigos desorganizados, difíceis de entender e de dar manutenção no futuro. Se você também acredita nisto, então fique à vontade em explorar meu blog.