純粋に理論的な観点からは、正しい行をロックしていないように見えます(最初のステートメントの条件はupdateステートメントとは異なります。さらに、LIMIT 1
のために1つの行のみをロックします 、ただし、後でさらに行を更新する可能性があります。
これを試してください:
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;
[編集]
デッドロックの理由としては、これが考えられる答えです(マニュアルから ):
インデックスがない場合、SELECT ... FOR UPDATE
ステートメントはテーブル全体をロックする可能性がありますが、インデックスを使用すると、一部の行のみがロックされます。最初のステートメントで正しい行をロックしなかったため、2番目のステートメントで追加のロックが取得されます。
明らかに、テーブル全体がロックされている場合(つまり、インデックスがない場合)、デッドロックは発生しません。2番目のセットアップでは確実にデッドロックが発生する可能性があります。