Comment implémenter correctement le verrouillage optimiste dans MySQL?
Notre équipe a déduit que nous devons faire # 4 ci-dessous, sinon il y a un risque qu'un autre thread puisse mettre à jour la même version de l'enregistrement, mais nous aimerions valider que c'est la meilleure façon de le faire.
- Créez un champ de version sur la table que vous souhaitez utiliser un verrouillage optimiste pour par exemple le nom de colonne = "version"
- Sur les sélections, assurez-vous d'inclure la colonne de version et notez la version
- Lors d'une mise à jour ultérieure de l'enregistrement, l'instruction de mise à jour doit émettre "où version = X" où X est la version que nous avons reçue dans # 2 et définir le champ de version pendant cette instruction de mise à jour sur X + 1.
- Effectuez une
SELECT FOR UPDATE
sur l'enregistrement que nous allons mettre à jour afin de sérialiser qui peut apporter des modifications à l'enregistrement que nous essayons de mettre à jour.
Pour clarifier, nous essayons d'empêcher deux threads qui sélectionnent le même enregistrement dans la même fenêtre de temps où ils saisissent la même version de l'enregistrement de se remplacer les uns les autres s'ils devaient essayer de mettre à jour l'enregistrement en même temps. Nous pensons que si nous ne faisons pas # 4, il y a une chance que si les deux threads entrent leurs transactions respectives en même temps (mais n'ont pas encore publié leurs mises à jour), quand ils vont mettre à jour, le deuxième thread qui utilisera la MISE À JOUR ... où version = X fonctionnera sur les anciennes données.
Avons-nous raison de penser que nous devons effectuer ce verrouillage pessimiste lors de la mise à jour, même si nous utilisons des champs de version / verrouillage optimiste?
SELECT ... FOR UPDATE
verrouillage optimiste ou par version de ligne, pas des deux. Voir détail en réponse.Réponses:
Votre développeur se trompe. Vous avez besoin d' une version
SELECT ... FOR UPDATE
ou d'une version en ligne, pas des deux.Essayez-le et voyez. Ouvrez trois sessions de MySQL
(A)
,(B)
et(C)
à la même base de données.En
(C)
cause:Dans les deux
(A)
et(B)
émettez unUPDATE
qui teste et définit la version de la ligne, en changeant lewinner
texte dans chacun afin que vous puissiez voir quelle session est laquelle:Maintenant
(C)
,UNLOCK TABLES;
pour libérer le verrou.(A)
et(B)
courra pour le verrouillage de la ligne. L'un d'eux gagnera et obtiendra le cadenas. L'autre bloquera la serrure. Le gagnant qui a obtenu le verrou procédera au changement de ligne. En supposant que(A)
c'est le gagnant, vous pouvez maintenant voir la ligne modifiée (toujours non validée, donc non visible pour les autres transactions) avec aSELECT * FROM test WHERE id = 1
.Maintenant
COMMIT
dans la session gagnante, disons(A)
.(B)
va obtenir le verrou et procéder à la mise à jour. Cependant, la version ne correspond plus, elle ne modifiera donc aucune ligne, comme indiqué par le résultat du nombre de lignes. Un seul aUPDATE
eu un effet, et l'application cliente peut clairement voir laquelle aUPDATE
réussi et qui a échoué. Aucun verrouillage supplémentaire n'est nécessaire.Voir les journaux de session sur pastebin ici . J'ai utilisé
mysql --prompt="A> "
etc pour faire facilement la différence entre les sessions. J'ai copié et collé la sortie entrelacée dans une séquence temporelle, donc ce n'est pas une sortie totalement brute et il est possible que j'aurais pu faire des erreurs en la copiant et en la collant. Testez-le vous-même pour voir.Si vous aviez pas ajouté un champ de version de la ligne, alors vous devez
SELECT ... FOR UPDATE
être en mesure d'assurer de manière fiable la commande.Si vous y réfléchissez, a
SELECT ... FOR UPDATE
est complètement redondant si vous faites immédiatement unUPDATE
sans réutiliser les données de laSELECT
, ou si vous utilisez le versionnage de ligne. LeUPDATE
prendra une serrure de toute façon. Si quelqu'un d'autre met à jour la ligne entre votre lecture et votre écriture ultérieure, votre version ne correspondra plus, votre mise à jour échouera. Voilà comment fonctionne le verrouillage optimiste.Le but de
SELECT ... FOR UPDATE
:SERIALIZABLE
isolation ou la gestion des versions de ligne.Vous n'avez pas besoin d'utiliser à la fois le verrouillage optimiste (version de ligne) et
SELECT ... FOR UPDATE
. Utilise l'un ou l'autre.la source
Aucun verrou (pas de table, pas de transaction) nécessaire ou même souhaité:
la source