Lock da Chave Seguinte: Evitando Problemas com Fantasmas


Em um lock de registro o InnoDB utiliza um algoritmo chamado trava de chave seguinte. O InnoDB faz o lock de registro, assim quando ele faz uma busca ou varre a tabela, ele atribui travas compartilhadas ou exclusivas nos registros que ele encontra. Assim o bloqueio de registro é mais precisamente chamado lock de registro de índice.

A trava que o InnoDB atribui em registro de índices também afetas as 'lacunas' antes daquele registro de índice. Se um usuário tem uma trava compartilhada ou exclusiva no registro R em um índice, então outro usuário não pode inserir um novo registro de índice imediatamente antes de R na ordem do índice. Este bloqueio de lacunas é feito para prevenir o chamado problema de fantasma. Suponha que eu queira ler e travar todos os filhos com identificador maior que 100 da tabela CHILD e atualizar alguns campos nos registros selecionados.

SELECT * FROM CHILD WHERE ID > 100 FOR UPDATE;

Suponha que exista um índice na tabela CHILD na coluna ID. Nossa consulta varrerá aquele índice começando do primeiro registro onde ID é maior que 100. Agora, se a trava atribuída no registro de índice não travasse inserções feitas nas lacunas, um novo filho poderia ser inserido na tabela. Se agora eu executasse em minha transação

SELECT * FROM CHILD WHERE ID > 100 FOR UPDATE;

novamente, eu veria um novo filho no resultado que a consulta retorna. Isto é contra o princípio de isolamento das transações: uma transação deve executar sem que os dados que ele estaja lendo sejam alterados durante a transação. Se considerarmos um conjunto de registros como um item de dados, então o novo filho 'fantasma' quebrará o principio do isolamento.

Quando o InnoDB varre um índice ele também pode bloquear a lacuna depois do último registro no índice. Assim como no exemplo anterior: a trava atribuida pelo InnoDB irá previnir que seja feita qualquer inserção na tabela onde ID seja maior que 100.

Você pode utilizar trava de chave seguinte para implementar uma verificação de unicidade em sua aplicação: se você ler os seus dados em modo compartilhado e não ver um registro que duplique o que você irá inserir, então você pode inserí-lo com segurança e saber que o trava de chave seguinte atribuida ao registro sucessor ao seu durante a leitura irá previnir que alguém insira um registro que duplique o seu neste intervalo. Assim a trava de chave seguinte permite que você 'bloqueie' a não existência de algo em sua tabela.

Retornar