MySQL Innodb bloqueando apenas as linhas afetadas?
-
22-09-2019 - |
Pergunta
Eu tenho uma tabela Innodb que contém usuários, assim:
+--------------+-----------------------+
| user_id | name |
+--------------+-----------------------+
| 1 | Bob |
| 1 | Marry |
| 2 | Bob |
| 1 | John |
| 3 | Bob |
| 2 | Marry |
+--------------+-----------------------+
Em cada inserção, incremento user_id em 1, por exemplo, o próximo user_id para Bob será 4
Eu uso esta consulta para fazer isso:
INSERT INTO users (user_id, name)
SELECT 1 + coalesce((SELECT max(user_id) FROM users WHERE name='Bob'), 0), 'Bob';
Agora preciso garantir que dois usuários diferentes não adicionem um 'bob' ao mesmo tempo. Não quero dois bobs com user_id 4. Cada um dos IDs de usuário de Bob deve ser diferente.
É possível escrever e atualizar o bloqueio de todas as linhas de Bob quando a consulta de inserção acima é executada? Não posso trancar a tabela inteira porque muitos outros usuários ainda precisam de acesso total às suas linhas. Além disso, todas as linhas devem ser legíveis o tempo todo. Como eu faria isso?
Solução
Assumindo innodb aqui, você pode usar Selecione ... Modo de bloqueio Para bloquear as linhas quando você as selecionar.
Outras dicas
Para resolver a primeira parte da sua pergunta, crie um índice exclusivo em user_id e nome.
alter table `users` add unique index ak_user_id_name(user_id,name);
Isso impedirá o user_id duplicado, o nome registra.
A resposta para esta pergunta é a mesma que Este. O Innodb bloqueará mais linhas aqui do que você espera por segurança com o registro binário baseado em declaração.
A solução: Use o log binário baseado em linha com o nível de isolamento de leitura-compromisso.