Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

Bloqueio de nível de linha no MySQL


Em vez de FOR UPDATE use LOCK IN SHARE MODE . FOR UPDATE impede que outras transações leiam a linha também. LOCK IN SHARE MODE permite a leitura, mas impede a atualização.

Referência:Manual MySQL

------ sessão 1
START TRANSACTION;
SELECT * FROM test WHERE t=1 LOCK IN SHARE MODE;
UPDATE test SET NAME='irfandd' WHERE t=2;
COMMIT;

----- sessão 2 (que não está mais sendo bloqueada :))
START TRANSACTION;
UPDATE test SET NAME='irfandd' WHERE t=4;
COMMIT;

Atualização:

Percebendo que a tabela não tem índice em t , tenho a seguinte explicação:

Primeiro, a transação T1 bloqueia a linha 1 em SELECT * FROM test WHERE t=1 FOR UPDATE

Em seguida, a transação T2 tenta executar UPDATE test SET NAME='irfandd' WHERE t=4 . Para descobrir quais linhas são afetadas, ele precisa verificar todas as linhas, incluindo linha 1 . Mas isso está bloqueado, então T2 deve esperar até que T1 termine. Se houver algum tipo de índice, o WHERE t=4 pode usar o índice para decidir se a linha 1 contém t=4 ou não, então não há necessidade de esperar.

Opção 1: adicione um índice em test.t para que sua atualização possa usá-lo.

Opção 2: use LOCK IN SHARE MODE , que se destina a colocar apenas um bloqueio de leitura. Infelizmente esta opção cria um impasse. Curiosamente, a transação T2 é executada (atualizando a linha 4) e a T1 falha (atualizando a linha 2). Parece que o T1 bloqueia a linha 4 também, e como o T2 o modifica, o T1 falha devido ao nível de isolamento da transação (LEITURA REPETÍVEL por padrão ). A solução final seria brincar com Níveis de isolamento de transação , usando READ UNCOMMITTED ou READ COMMITTED níveis de transação.

A mais simples é a Opção 1 , IMHO, mas depende de suas possibilidades.