Le verrouillage des tables empêche les autres utilisateurs de la base de données d'affecter les lignes/tables que vous avez verrouillées. Mais les verrous, en eux-mêmes, ne garantiront PAS que votre logique sortira dans un état cohérent.
Pensez à un système bancaire. Lorsque vous payez une facture en ligne, il y a au moins deux comptes concernés par la transaction :Votre compte, à partir duquel l'argent est prélevé. Et le compte du destinataire, sur lequel l'argent est transféré. Et le compte de la banque, sur lequel ils se feront un plaisir de déposer tous les frais de service facturés sur la transaction. Étant donné (comme tout le monde le sait de nos jours) que les banques sont extraordinairement stupides, disons que leur système fonctionne comme ceci :
$balance = "GET BALANCE FROM your ACCOUNT";
if ($balance < $amount_being_paid) {
charge_huge_overdraft_fees();
}
$balance = $balance - $amount_being paid;
UPDATE your ACCOUNT SET BALANCE = $balance;
$balance = "GET BALANCE FROM receiver ACCOUNT"
charge_insane_transaction_fee();
$balance = $balance + $amount_being_paid
UPDATE receiver ACCOUNT SET BALANCE = $balance
Maintenant, sans verrous et sans transactions, ce système est vulnérable à diverses conditions de concurrence, dont la plus importante est les paiements multiples effectués sur votre compte ou sur le compte du destinataire en parallèle. Pendant que votre code récupère votre solde et fait le énorme_overdraft_fees() et ainsi de suite, il est tout à fait possible qu'un autre paiement exécute le même type de code en parallèle. Ils récupéreront votre solde (par exemple, 100 $), effectueront leurs transactions (retirez les 20 $ que vous payez et les 30 $ avec lesquels ils vous baisent), et maintenant les deux chemins de code ont deux soldes différents :80 $ et 70 $. Selon ceux qui finissent en dernier, vous vous retrouverez avec l'un ou l'autre de ces deux soldes sur votre compte, au lieu des 50 $ avec lesquels vous auriez dû vous retrouver (100 $ - 20 $ - 30 $). Dans ce cas, "erreur bancaire en votre faveur".
Maintenant, disons que vous utilisez des verrous. Le paiement de votre facture (20 $) arrive en premier dans le tuyau, il gagne donc et verrouille l'enregistrement de votre compte. Vous avez maintenant un usage exclusif et pouvez déduire les 20 $ du solde et réécrire le nouveau solde en toute tranquillité... et votre compte se retrouve avec 80 $ comme prévu. Mais... uhoh... Vous essayez d'aller mettre à jour le compte du destinataire, et il est verrouillé, et verrouillé plus longtemps que le code ne le permet, chronométrant votre transaction... Nous avons affaire à des banques stupides, donc au lieu d'avoir une erreur appropriée manipulation, le code tire juste un exit()
, et vos 20 $ disparaissent dans une bouffée d'électrons. Maintenant, il vous manque 20 $, et vous devez toujours 20 $ au destinataire, et votre téléphone est repris.
Alors... entrez les transactions. Vous démarrez une transaction, vous débitez votre compte de 20 $, vous essayez de créditer le destinataire de 20 $... et quelque chose explose à nouveau. Mais cette fois, au lieu de exit()
, le code peut simplement faire rollback
, et pouf, vos 20 $ sont ajoutés comme par magie à votre compte.
En fin de compte, cela se résume à ceci :
Les verrous empêchent quiconque d'interférer avec les enregistrements de base de données avec lesquels vous traitez. Les transactions empêchent toute erreur " ultérieure " d'interférer avec les actions " antérieures " que vous avez effectuées. Ni l'un ni l'autre ne peuvent garantir que les choses se passent bien à la fin. Mais ensemble, ils le font.
dans la leçon de demain :La joie des impasses.