Back-End

13 nov, 2008

MySQL Locking

Publicidade

Este artigo tem como principal objetivo trazer o conhecimento e formar habilidades para o leitor em conceitos e práticas relacionados com características e tipos de bloqueios, também chamados de LOCK, que acontecem em tabelas de bancos de dados do servidor de bancos de dados MySQL.

Os bloqueios se fazem importantes a partir do momento em que se pretende trabalhar de forma isolada com algumas tabelas dos bancos de dados para que não haja nenhum interferência em uma determinada manipulação, evitando concorrências, seja através do mysql client, conforme mostraremos aqui, seja em meio a operações de uma aplicação que utiliza o MySQL como back-end.

Após ler este artigo, você estará apto a:

  • Conceituar os bloqueios ou LOCKing;
  • Tipos de bloqueios ou LOCKing;
  • Utilizar bloqueios explícitos;

Conceitos de Locking ou Bloqueio em Tabelas

O servidor de bancos de dados MySQL utiliza sua arquitetura multi-threaded para garantir conexões com ele a todos os usuários simultaneamente. Para cada cliente que se conecta ao servidor de bancos de dados MySQL, este alocará uma thread como um controlador. Caso um usuário, conectado através de um cliente qualquer, acessa várias tabelas ao mesmo tempo que outros usuários, provenientes de outros clientes, uma conexão não interfere na outra, ou seja, cada conexão tem a sua vez de leitura ou escrita em uma mesma tabela.

Nesse acesso simultâneo, alguns problemas podem acontecer quando dois clientes têm usuários manipulando o mesmo dado. Para o primeiro cliente, um bloqueio é adquirido para que este, ao terminar de fazer suas manipulações nos dados, tenha seu bloqueio cancelado, passando a vez para uma outra manipulação nos mesmos dados. Em outras palavras, os bloqueios serializam os acessos ao mesmo dado. Enquanto uma dada operação A adquire um LOCK em uma tabela X, para que B manipule dados nessa mesma tabela, terá que esperar, dependendo do tipo de LOCK adquirido por A na tabela X e, também, de qual operação B fará sobre a tabela X.

Note que alguns conflitos são percebidos em situações em que dois comandos ou grupo manipulem a mesma linha ao mesmo tempo. Para garantir que não haja conflitos, podemos enviar ao SGBD um pedido de bloqueios em tabelas, tanto um bloqueio de leitura quanto um bloqueio de escrita.

Tipos Bloqueios ou LOCKing

Bloqueios sobre dados podem ser adquiridos de maneira implícita, explícita ou com advisory locks:

Para clientes que trabalham com configurações do modo autocommit habilitado (padrão do MySQL), o servidor MySQL adquire bloqueios implicitamente para cada comando que chega ao servidor e cancela o bloqueio logo que este finaliza. Por exemplo, o servidor MySQL adquire um LOCK de leitura para um comando SELECT e um LOCK de escrita para o comando INSERT. Após finalizadas as operações, o LOCK é desfeito com um UNLOCK TABLES interno;

Caso um bloqueio implícito seja insuficiente, podemos bloquear as tabelas através do comando LOCK TABLES e soltar esse bloqueio através do comando UNLOCK TABLES, de maneira explícita. Bloqueios explícitos normalmente são adquiridos quando se deseja trabalhar com múltiplos comandos sem interferência de outras operações de outros clientes conectados no mesmo banco de dados. Um exemplo é quando precisamos trabalhar vários comandos utilizando a função LAST_INSERT_ID(), caso não travemos novas inserções na tabela que originou o valor retornado pela função LAST_INSERT_ID(), pode ser que no meio das operações com o banco dados, LAST_INSERT_ID() tenha outro valor, pois uma nova inserção concorrente poderá acontecer;

Outro tipo de bloqueio é o bloqueio denominado Advisory Locking. Diferentemente dos bloqueios implícitos e explícitos, Advisory Locks não são gerenciados pelo servidor MySQL, os próprios clientes gerenciam os bloqueios usando um conjunto de funções que eles próprios podem utilizar.

Utilizando Bloqueios Explícitos

Clientes gerenciam explicitamente o bloqueio de tabelas com duas declarações: LOCK TABLES para adquirir bloqueio em uma ou mais tabelas e UNLOCK TABLES para cancelar os mesmos. A declaração LOCK TABLES fornece os nomes das tabelas que desejamos efetuar o bloqueio e também o tipo de bloqueio que precisamos que seja efetuado.

Utilizando o banco de dados world (disponível em http://downloads.mysql.com/docs/world.sql.zip) para nossos exemplos práticos, abaixo utilizamos LOCK TABLES para adquirir dois bloqueios ao mesmo tempo, o primeiro de leitura – READ – na tabela Country e outro de escrita – WRITE – para a tabela City.

mysql> LOCK TABLES Country READ, City WRITE;
Query OK, 0 rows affected (0.39 sec)

Caso as tabelas de uma declaração LOCK TABLES estejam em uso exatamente no momento em que um bloqueio explícito é solicitado, tal pedido aguardará até que possa adquiri-lo. Podemos ver no teste feito na Figura 01 que, caso um usuário B solicite um bloqueio em uma tabela já bloqueada por outro usuário A, em conexões simultâneas, esta solicitação aguardará até que o bloqueio A seja cancelado, liberando a tabela.

Demonstração de bloqueio para a tabela City:

Perceba na imagem acima que quando o usuário B se conecta ao servidor MySQL e solicita um bloqueio de escrita – WRITE – o prompt fica aguardando até que A libere seu bloqueio na tabela para que B adquira o seu bloqueio.

Um bloquieio do tipo WRITE é também conhecido como bloqueio exclusivo, ou seja, se uma determinada conexão bloquear uma tabela com essa opção, nenhuma outra conexão poderá ler e escrever nesta tabela, enquanto que um bloqueio READ é um bloqueio adquirido em uma tabela de forma compartilhada, ou seja, outras conexões somente poderão ler a tabela, não escrever.

Para que você utilize a declaração LOCK TABLES para adquirir bloqueios em tabelas de um banco de dados no servidor de bancos de dados MySQL, é necessário que o seu usuário tenha privilégios LOCK TABLES e SELECT para cada tabela que se deseja adquirir o bloqueio.

No próximo artigo trabalharemos um estudo de caso em parceria com a linguagem PHP para ilustrarmos um exemplo com LOCK TABLES. Tenho recebido muitos e-mails solicitando exemplos com TRIGGERS, recurso que é muito útil em várias situações e também publicarei um estudo de caso, aplicando tal recurso.

Happy MySQL’ing!