Observar versão e configuração
O ensaio usa MySQL Community Server 9.7.2 para macOS, com InnoDB e três ligações próprias por instância. A referência do percurso continua a série 9.7 LTS; a nota 9.7.3 refere-se apenas à imagem Docker e não renomeia este binário. A configuração observada inclui REPEATABLE READ e o valor de innodb_rollback_on_timeout. Regista também autocommit e início explícito das transações, porque um driver pode ter defaults diferentes do servidor. Não deduzas o comportamento da aplicação apenas a partir do nome da tecnologia. O guião usa dados fictícios, socket privado, contas locais de laboratório e nenhum serviço permanente.
Comparar leitura consistente e locking read
A sessão A inicia uma transação e lê units=100. B atualiza para 90 e confirma. A repete o SELECT simples e continua a ver 100; SELECT FOR UPDATE devolve 90. Um novo SELECT simples na mesma transação volta a devolver 100. O contraste mostra por que motivo não se deve descrever todos os comandos como leitura da mesma snapshot. A decisão de alteração deve usar o mecanismo transacional adequado ao requisito e não combinar valores de contextos diferentes sem análise. No incidente, recolhe a sequência dos comandos e commits; duas consultas com resultados diferentes não demonstram, isoladamente, perda ou corrupção.
Testar o contrato em READ COMMITTED
Depois de terminar a transação anterior, A passa para READ COMMITTED. A primeira leitura devolve 90; B confirma 80; a leitura seguinte de A devolve 80 ainda dentro da mesma transação. Este resultado distingue o momento da snapshot da fronteira de commit do leitor. READ COMMITTED não significa ausência de transações, nem protege automaticamente uma decisão read-modify-write. Antes de mudar o isolamento para resolver um sintoma, identifica leituras repetidas, invariantes e possíveis alterações concorrentes. O laboratório compara uma linha numa sequência controlada; não mede throughput nem demonstra que esta alteração seja adequada para todo um serviço de fundos.
Relacionar transações e ligações em espera
Quando B tenta atualizar a linha retida por A, a observação consulta performance_schema.data_lock_waits e associa os thread IDs a performance_schema.threads. Assim chega aos PROCESSLIST_ID obtidos das ligações próprias. A relação é observada enquanto a query está efetivamente à espera, antes de enviar qualquer intervenção. Não uses o ID de um lock como se fosse o identificador de ligação aceite por KILL. Num ambiente real, correlaciona a relação com dono funcional, transação e impacto antes de agir. O laboratório usa root apenas dentro da instância descartável e não demonstra permissões de observação de uma conta de produção.
Escolher entre espera, NOWAIT e SKIP LOCKED
Com a linha 1 bloqueada por A, NOWAIT devolve erro 3572. SKIP LOCKED, numa query sobre as duas linhas, devolve apenas id 2. Os modos exprimem contratos diferentes: recusar a contenção ou continuar com o subconjunto disponível. Não são provas de que a linha 1 deixou de existir. Estes modificadores dizem respeito a locks de linha; não eliminam toda a possibilidade de espera noutros recursos. Para uma fila, a omissão pode ser deliberada. Para reconciliação ou total de posições, omitir linhas temporariamente pode produzir uma conclusão errada. Define o comportamento esperado antes de escolher a sintaxe.
Separar seleção de execução de tarefas
Depois do rollback das transações de seleção, uma nova query SKIP LOCKED devolve ids 1 e 2. O ensaio mostra elegibilidade recuperada quando os locks são libertados, mas não implementa um worker nem confirma entrega exatamente uma vez. Uma fila real precisa de estado de tarefa, transação de claim, prazo de posse e recuperação de efeitos externos. Se um worker deixa de responder após enviar uma operação, o desaparecimento do lock não esclarece se o efeito aconteceu. Usa identidade estável e reconciliação apropriada. Mantém estes requisitos separados da pequena prova de seleção concorrente realizada neste laboratório.
SELECT VERSION(), @@session.transaction_isolation;
START TRANSACTION;
SELECT units FROM balances WHERE id=1;
-- The other owned session updates and commits before the next statements.
SELECT units FROM balances WHERE id=1;
SELECT units FROM balances WHERE id=1 FOR UPDATE;
ROLLBACK;Na mesma transação REPEATABLE READ, SELECT simples mantém 100 enquanto FOR UPDATE lê 90 depois do commit de outra sessão.
Armadilhas comuns
Tratar todas as leituras como a mesma snapshot; usar SKIP LOCKED como inventário completo; confundir thread ID com connection ID.
Tópicos relacionados: Concorrência e identidade da ligação · Atomicidade e aceitação operacional
O diagnóstico deve identificar modo de leitura, fronteira transacional e relação concreta entre quem espera e quem bloqueia.
Referência: Consistent nonlocking reads · MySQL 9.7 LTS with InnoDB reference semantics