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

Comment utiliser correctement les transactions et les verrous pour assurer l'intégrité de la base de données ?

Jusqu'ici tout va bien, cela empêchera au moins l'utilisateur d'effectuer le paiement en plusieurs sessions (plusieurs fois en essayant de payer la même carte - bon pour gérer les doubles clics.)

Comment vérifiez-vous? Avec un SELECT standard ou avec un SELECT ... FOR UPDATE ? Sur la base de l'étape 5, je suppose que vous vérifiez une colonne réservée sur l'élément, ou quelque chose de similaire.

Le problème ici est que le SELECT ... FOR UPDATE à l'étape 2 ne va PAS appliquer le FOR UPDATE verrouiller sur tout le reste. Il ne s'applique qu'à ce qui est SELECT ed :le cart-item table. En fonction du nom, il s'agira d'un enregistrement différent pour chaque panier/utilisateur. Cela signifie que les autres transactions ne seront PAS bloquées.

Suite à ce qui précède, sur la base des informations que vous avez fournies, vous pouvez vous retrouver avec plusieurs personnes achetant le même article, si vous n'utilisez pas SELECT ... FOR UPDATE à l'étape 3.

Solution suggérée

  1. Commencer la transaction
  2. SELECT ... FOR UPDATE le cart-item tableau.

Cela empêchera un double-clic de s'exécuter. Ce que vous sélectionnez ici devrait être une sorte de colonne "panier commandé". Si vous faites cela, une deuxième transaction s'arrêtera ici et attendra la fin de la première, puis lira le résultat que la première a enregistré dans la base de données.

Assurez-vous de terminer le processus de paiement ici si le cart-item table indique qu'il a déjà été commandé.

  1. SELECT ... FOR UPDATE le tableau dans lequel vous enregistrez si un article a été réservé.

Cela empêchera les AUTRES paniers/utilisateurs de lire ces éléments.

En fonction du résultat, si les articles ne sont pas réservés, continuez :

  1. UPDATE ... le tableau à l'étape 3, en marquant l'élément comme réservé. Faites tout autre INSERT s et UPDATE s dont vous avez également besoin.

  2. Effectuer le paiement. Effectuez une annulation si le service de paiement indique que le paiement n'a pas fonctionné.

  3. Enregistrer le paiement, en cas de succès.

  4. Valider la transaction

Assurez-vous de ne rien faire qui pourrait échouer entre les étapes 5 et 7 (comme l'envoi d'e-mails), sinon vous pourriez vous retrouver avec un paiement sans qu'il soit enregistré, au cas où la transaction serait annulée.

L'étape 3 est l'étape importante pour s'assurer que deux personnes (ou plus) n'essaient pas de commander le même article. Si deux personnes essaient, la 2ème personne finira par voir sa page Web "se bloquer" pendant qu'elle traite la première. Ensuite, lorsque le premier se termine, le 2ème lira la colonne "réservé", et vous pourrez renvoyer un message à l'utilisateur indiquant que quelqu'un a déjà acheté cet article.

Paiement en transaction ou non

C'est subjectif. En règle générale, vous souhaitez clôturer les transactions le plus rapidement possible, afin d'éviter que plusieurs personnes ne soient empêchées d'interagir avec la base de données à la fois.

Cependant, dans ce cas, vous voulez vraiment qu'ils attendent. C'est juste une question de combien de temps.

Si vous choisissez de valider la transaction avant le paiement, vous devrez enregistrer votre progression dans une table intermédiaire, exécuter le paiement, puis enregistrer le résultat. Sachez que si le paiement échoue, vous devrez alors annuler manuellement les enregistrements de réservation d'articles que vous avez mis à jour.

SELECT ... FOR UPDATE sur des lignes inexistantes

Juste un mot d'avertissement, au cas où la conception de votre tableau impliquerait l'insertion de lignes là où vous devez auparavant SELECT ... FOR UPDATE  :Si une ligne n'existe pas, cette transaction NE provoquera PAS l'attente d'autres transactions, si elles SELECT ... FOR UPDATE la même ligne inexistante.

Assurez-vous donc de toujours sérialiser vos requêtes en faisant un SELECT ... FOR UPDATE sur une ligne dont vous savez qu'elle existe en premier. Ensuite, vous pouvez SELECT ... FOR UPDATE sur la ligne qui peut ou non exister encore. (N'essayez pas de faire juste un SELECT sur la ligne qui peut ou non exister, car vous lirez l'état de la ligne au moment où la transaction a commencé, pas au moment où vous exécutez le SELECT . Donc, SELECT ... FOR UPDATE sur des lignes inexistantes est toujours quelque chose que vous devez faire afin d'obtenir les informations les plus à jour, sachez simplement que cela ne fera pas attendre d'autres transactions.)