Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment éviter MySQL 'Deadlock trouvé lors d'une tentative de verrouillage; essayez de redémarrer la transaction'

Une astuce simple qui peut aider avec la plupart des blocages consiste à trier les opérations dans un ordre spécifique.

Vous obtenez un interblocage lorsque deux transactions tentent de verrouiller deux verrous à des ordres opposés, c'est-à-dire :

  • connexion 1 :verrouille la clé(1), verrouille la clé(2) ;
  • connexion 2 :verrouille la clé (2), verrouille la clé (1) ;

Si les deux s'exécutent en même temps, la connexion 1 verrouillera la clé (1), la connexion 2 verrouillera la clé (2) et chaque connexion attendra que l'autre libère la clé -> blocage.

Maintenant, si vous modifiez vos requêtes de sorte que les connexions verrouillent les clés dans le même ordre, c'est-à-dire :

  • connexion 1 :verrouille la clé(1), verrouille la clé(2) ;
  • connexion 2 : verrouille la clé (1 ), verrouille la clé (2 );

il sera impossible d'obtenir une impasse.

Voici donc ce que je propose :

  1. Assurez-vous qu'aucune autre requête ne verrouille l'accès à plusieurs clés à la fois, à l'exception de l'instruction de suppression. si vous le faites (et je suppose que vous le faites), classez leur WHERE en (k1,k2,..kn) par ordre croissant.

  2. Corrigez votre instruction de suppression pour qu'elle fonctionne par ordre croissant :

Modifier

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;

Une autre chose à garder à l'esprit est que la documentation MySQL suggère qu'en cas d'impasse, le client doit réessayer automatiquement. vous pouvez ajouter cette logique à votre code client. (Disons, 3 tentatives sur cette erreur particulière avant d'abandonner).