De um ponto de vista puramente teórico, parece que você não está bloqueando as linhas corretas (condição diferente na primeira instrução do que na instrução de atualização; além disso, você bloqueia apenas uma linha por causa de
LIMIT 1
, enquanto você possivelmente atualiza mais linhas posteriormente). Tente isto:
START TRANSACTION;
SELECT v_id FROM v_ext WHERE username IS NULL AND v_id=yyy FOR UPDATE;
UPDATE v_ext SET username=xxx WHERE v_id=yyy;
COMMIT;
[editar]
Quanto ao motivo do seu impasse, esta é a resposta provável (do manual ):
Sem um índice, o
SELECT ... FOR UPDATE
É provável que a instrução bloqueie a tabela inteira, enquanto que com um índice, ela bloqueia apenas algumas linhas. Como você não bloqueou as linhas corretas na primeira instrução, um bloqueio adicional é adquirido durante a segunda instrução. Obviamente, um deadlock não pode ocorrer se toda a tabela estiver bloqueada (ou seja, sem um índice). Um deadlock certamente pode ocorrer na segunda configuração.