Para que serve uma MySQL Transaction?

mm

Ramos de Souza Janones

Janones, é um empreendedor brasileiro apaixonado por empreendedorismo e tecnologia. Ao longo dos anos trabalhando com o desenvolvimento de softwares desktop desde a linguagem Clipper, passando pelo Delphi e atualmente com Java.

Optou pela formação de Publicidade e Marketing por sua segunda empresa de tecnologia ter participado do "boom" da internet nos anos 90 e na procura de melhorar seus conhecimentos em negócios.

Em razão da principal formação e profundos conhecimentos em programação e banco de dados, é capaz de realizar o desenvolvimento de aplicativos web, desktop e mobile com maior criatividade e inovação que profissionais de desenvolvimento com uma formação única e mais especifica, dedicada somente ao desenvolvimento de softwares.

Com toda sua experiência com empresas de software, sua formação e paixão por negócios escreveu o livro "Marketing para Empresas e Profissionais de Software", publicado pela editora carioca Ciência Moderna em 2012. Além de outros livros sobre programação.
mm

Bancos de dados SQL em geral, não somente o MySQL, são transacionais, isto é, eles permitem você executar uma sequência de operações como um bloco indivisível de forma a garantir a integridade dos dados em um ambiente com acesso concorrente.

O Problema

No exemplo citado na pergunta, imagine que as queries #1, #2 e #3 são operações que afetam a base de dados e não usamos uma transação para controlá-las. Vamos usar como exemplo um e-commerce:

  1. Atualiza dados de entrega do cliente
  2. Insere um novo registro da compra efetuada, verificando se possui estoque
  3. Debita o estoque dos produtos

Agora imagine dois clientes tentando finalizar suas compras neste e-commerce fictício. O servidor recebe duas requisições quase simultaneamente e começa a processar os pedidos na sequência apresentada acima. Os dois pedidos estão sendo processados simultaneamente em threads diferentes.

Imagine ainda que tanto o cliente A quanto o cliente B selecionaram um produto que tem apenas uma unidade em estoque. Podemos acabar com a seguinte linha de execução:

  1. Thread A atualiza dados do cliente A (passo #1), verifica o estoque insere o registro da compra (passo #2)
  2. A thread A é bloqueada e B passa a ser executada
  3. Thread B atualiza dados do cliente B (passo #1), verifica o estoque insere o registro da compra (passo #2)
  4. Thread B atualiza o estoque, que agora fica zerado
  5. A thread B é bloqueada e A passa a ser executada
  6. Thread A atualiza o estoque, que agora fica negativo!

Note que apesar do código verificar o estoque a ordem de execução faz com que a verificação não seja garantida no passo seguinte.

A Solução

Bancos de dados transacionais usam o conceito ACID:

  • Atomicidade: uma transação é uma sequência de operações indivisível, ou é executado como um todo, ou tudo é desfeito.
  • Consistência: ao final da transação, o estado dos dados deve ser consistente.
  • Isolamento: embora alguns sistemas permitam quebrar o isolamento, em geral, uma transação em andamento não pode ser acessada por outras transações de modo a evitar leitura de um estado inconsistente, uma “sujeira”.
  • Durabilidade: em caso de sucesso (commit) a persistência dos dados deve ser garantida

Para garantir esses conceitos, em geral, os bancos de dados usam bloqueios quando ocorrem acessos simultâneos à mesma estrutura de dados. Ou seja, se alguém já está mexendo nos dados, os demais tem que esperar ele acabar e aguardar sua vez na fila.

Na prática

Ao usar bancos de dados transacionais, nós podemos usufruir deste controle de gerenciamento por parte dos SGBDRs (Sistemas Gerenciadores de Bancos de Dados Relacionais).

Incluindo o conceito de transação ACID no exemplo anterior, vamos ver como fica a execução:

  1. Thread A inicia uma transação, atualiza dados do cliente A (passo #1), verifica o estoque insere o registro da compra (passo #2)
  2. A thread A é bloqueada e B passa a ser executada
  3. Thread B inicia uma transação, mas ao tentar atualizar os dados do cliente B ela é bloqueada porque a transação de A ainda não acabou
  4. Thread A atualiza o estoque, que agora fica zerado, e faz commit na transação.
  5. A thread B é desbloqueada e passa a ser executada
  6. A thread B atualiza dados do cliente B (passo #1), verifica o estoque e retorna um erro pois não encontra o produto disponível
  7. Thread B executa um rollback para desfazer as alterações que já havia efetuado

O resultado final é como se somente a thread A tivesse executado e B nunca existisse.

Nem tudo é um mar de rosas

Existem alguns problemas inerentes às transações ACID, sendo o desempenho o maior deles.

Embora seja importante garantir a integridade dos dados, para muitos sistemas onde a disponibilidade é o fator mais crítico, um modelo que bloqueia acessos simultâneos torna-se inviável.

Este é um dos principais fatores para o surgimento e a adoção de diversos sistemas de bancos de dados não transacionais e NoSQL.

O importante é entender que o uso de transações tem um custo e em algumas ocasiões este pode ser alto demais. Uma das representações mais comuns do trade-off de persistência de dados é a seguinte (retirada deste artigo):

Trade-off entre propriedades de bancos de dados

O gráfico demonstra que consistência, disponibilidade e particionamento (escalar o banco de dados em diversos nós) são recursos que afetam uns aos outros. Você simplesmente não pode ter o melhor dos três, segundo o teorema de CAP.

Bancos de dados relacionais geralmente sacrificam o particionamento em prol da consistência e da disponibilidade, enquanto alguns sistemas NoSQL sacrificam a consistência dos dados.

Compartilhe.

PinIt
Top