Digamos que temos duas tabelas user
e book
.
No nível do aplicativo, para garantir a integridade dos dados e evitar condições de corrida, bloqueamos a entidade no início da transação.
Questão 1:
Digamos que no nível do aplicativo temos duas solicitações em execução ao mesmo tempo:
Solicitação 1 (nível do aplicativo):
start trx
lock for update user with id 1
lock for update book with id 2
do changes
commit
Solicitação 2 (nível do aplicativo):
start trx
lock for update book with id 2
lock for update user with id 1
do changes
commit
Pode acontecer que ambos os primeiros bloqueios da solicitação sejam aplicados antes dos segundos bloqueios, solicitação de 1 bloqueio do usuário 1 e solicitação de 2 bloqueios do livro 2, o que resultará em bloqueio morto.
Como podemos evitar isso? Minha única idéia é escrever em algum lugar uma ordem de bloqueio para todas as tabelas user->book
e garantir que a sigamos.
Questão 2:
Se fizermos duas consultas como essa em solicitações diferentes para bloquear entidades antes da mutação
- Solicitação 1
SELECT * FROM user WHERE id IN [1,2] FOR UPDATE
- Solicitação 2
SELECT * FROM user WHERE id IN [2,1] FOR UPDATE
Isso pode resultar em impasse? Por exemplo, se UMA consulta por algum motivo bloquear o usuário 1 primeiro e depois mudar para a solicitação 2 e depois voltar para bloquear o usuário 2.