Le verrouillage des tables empêche les autres utilisateurs de 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, sur lequel l'argent est prélevé. Et le compte du séquestre, dans lequel l'argent est transféré. Et le compte de la banque, sur lequel ils déposeront avec plaisir tous les frais de service facturés lors de 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
Désormais, sans verrous ni transactions, ce système est vulnérable à diverses conditions de concurrence, dont la plus importante est plusieurs paiements effectués sur votre compte ou sur le compte du destinataire en parallèle. Bien que votre code ait récupéré votre solde et effectue les énormes_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 (disons 100 $), effectueront leurs transactions (retirez les 20 $ que vous payez et les 30 $ qu'ils vous foutent), et maintenant les deux chemins de code ont deux soldes différents: 80 $ et 70 $. En fonction de celui qui se termine en dernier, vous vous retrouverez avec l'un de ces deux soldes dans 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, il gagne et verrouille l'enregistrement de votre compte. Maintenant, vous avez une utilisation exclusive et pouvez déduire les 20 $ du solde, et réécrire le nouveau solde en paix ... et votre compte se termine avec 80 $ comme prévu. Mais ... euh ... vous essayez d'aller mettre à jour le compte du destinataire, et il est verrouillé, et verrouillé plus longtemps que le code ne le permet, expirant 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, vous êtes à 20 $ et vous devez toujours 20 $ au destinataire, et votre téléphone est repris.
Alors ... saisissez des 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 cela exit()
, le code peut tout simplement faire rollback
, et pouf, vos 20 $ sont ajoutés 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 la base de données que vous traitez. Les transactions empêchent les erreurs "ultérieures" d'interférer avec les choses "antérieures" que vous avez faites. 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: The Joy of Deadlocks.