ほとんどのデッドロックに役立つ簡単なトリックの1つは、操作を特定の順序で並べ替えることです。
2つのトランザクションが反対の順序で2つのロックをロックしようとすると、デッドロックが発生します。つまり、次のようになります。
- 接続1:キー(1)をロックし、キー(2)をロックします。
- 接続2:キー(2)をロックし、キー(1)をロックします。
両方が同時に実行される場合、接続1はkey(1)をロックし、接続2はkey(2)をロックし、各接続は他方がキーを解放するのを待ちます->デッドロック。
ここで、接続が同じ順序でキーをロックするようにクエリを変更した場合、つまり:
- 接続1:キー(1)をロックし、キー(2)をロックします。
- 接続2:キーをロックします( 1 )、キーをロックします( 2 );
デッドロックを起こすことは不可能です。
だからこれが私が提案するものです:
-
削除ステートメントを除いて、一度に複数のキーへのアクセスをロックするクエリが他にないことを確認してください。もしそうするなら(そしてあなたがそうするのではないかと思う)、(k1、k2、.. kn)のWHEREを昇順で並べてください。
-
削除ステートメントを昇順で機能するように修正します:
変更
DELETE FROM onlineusers
WHERE datetime <= now() - INTERVAL 900 SECOND
宛先
DELETE FROM onlineusers
WHERE id IN (
SELECT id FROM onlineusers
WHERE datetime <= now() - INTERVAL 900 SECOND
ORDER BY id
) u;
もう1つ覚えておくべきことは、MySQLのドキュメントでは、デッドロックが発生した場合にクライアントが自動的に再試行する必要があることを示しています。このロジックをクライアントコードに追加できます。 (たとえば、あきらめる前に、この特定のエラーを3回再試行します。)