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

Comment les tables innodb sont verrouillées lorsque le déclencheur ON INSERT est traité ?

A propos des problèmes de concurrence, vous avez un 'facile' moyen d'éviter tout problème de concurrence dans la 2ème méthode, dans votre transaction, effectuez une sélection sur la ligne des articles (le For update est maintenant implicite). Toute insertion concurrente sur le même article ne pourra pas obtenir ce même verrou et vous attendra.

Avec les nouveaux niveaux d'isolement par défaut, sans même utiliser le niveau de sérialisation dans la transaction, vous ne verriez aucune insertion simultanée sur la table de vote jusqu'à la fin de votre transaction. Ainsi, votre SUM doit rester cohérent ou sembler cohérent . Mais si une transaction concurrente insère un vote sur le même article et s'engage avant vous (et que cette 2ème ne voit pas votre insertion), la dernière transaction à s'engager écrasera le compteur et vous perdrez 1 vote. Effectuez donc un verrouillage de ligne sur l'article en utilisant une sélection avant (et faites votre travail dans une transaction, bien sûr). Il est facile de tester, d'ouvrir 2 sessions interactives sur MySQL et de démarrer des transactions avec BEGIN.

Si vous utilisez le déclencheur, vous êtes dans une transaction par défaut. Mais je pense que vous devriez également effectuer la sélection sur la table article pour créer un verrou de ligne implicite pour les déclencheurs simultanés en cours d'exécution (plus difficile à tester).

  • N'oubliez pas de supprimer les déclencheurs.
  • N'oubliez pas les déclencheurs de mise à jour.
  • Si vous n'utilisez pas de déclencheurs et de code restant, soyez prudent chaque requête d'insertion/suppression/mise à jour sur les votes doit effectuer un verrouillage de ligne sur l'article correspondant avant dans la transaction. Il n'est pas très difficile d'en oublier un.

Dernier point :faites des transactions plus difficiles, avant de commencer la transaction, utilisez :

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

De cette façon, vous n'avez pas besoin de verrous de ligne sur les articles, MySQL détectera qu'une écriture potentielle sur la même ligne se produit et bloquera les autres transactions jusqu'à ce que vous ayez terminé. Mais n'utilisez pas quelque chose que vous avez calculé à partir d'une requête précédente . La requête de mise à jour attendra une libération de verrou sur les articles, lorsque le verrou sera libéré par la 1ère transaction COMMIT le calcul de SUM doit être refait pour compter. La requête de mise à jour doit donc contenir le SUM ou faire un ajout.

update articles set nb_votes=(SELECT count(*) from vote) where id=2; 

Et ici, vous verrez que MySQL est intelligent, un blocage est détecté si 2 transactions tentent de le faire alors que l'insertion a été effectuée en même temps. Dans les niveaux de sérialisation, je n'ai pas trouvé de moyen d'obtenir une mauvaise valeur avec :

   SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
   BEGIN;
       insert into vote (...
       update articles set nb_votes=(
         SELECT count(*) from vote where article_id=xx
       ) where id=XX;
    COMMIT;

Mais soyez prêt à gérer la rupture de transaction que vous devez refaire.