La déduction des stocks dans le système de commerce électronique est une opération très critique. Par exemple, dans le système de vente flash, les conditions de survente doivent être évitées si le commerçant met en place 100 pièces en stock mais termine. en vendant 1 000 pièces, ce qui entraînera des pertes financières. L'énoncé suivant est généralement utilisé lors de la déduction des stocks :
udpate goods set stock = stock - #{acquire} where sku_id = #{skuId} and stock - #{acquire} >= 0
Analysons comment cet énoncé peut efficacement empêcher la survente des stocks afin de protéger les ressources d'inventaire. Dans la démonstration de cet article, nous utilisons le moteur MySQL Innodb et définissons le niveau d'isolation sur lecture répétable.
Le verrouillage partagé (verrouillage partagé) est également appelé verrouillage en lecture. L'instruction pour implémenter le verrouillage partagé est la suivante :
select lock in share mode
Le verrouillage exclusif (verrouillage exclusif) est également appelé verrouillage en écriture et implémente le verrouillage exclusif. L'instruction de verrouillage est la suivante :
select for update update delete insert
La relation de compatibilité entre les verrous partagés et les verrous exclusifs est la suivante :
Nous analysons la relation de compatibilité ci-dessus à travers des exemples. Tout d'abord, construisons une table de test et écrivons les données de test :
CREATE TABLE `test_account` ( `id` bigint(20) NOT NULL, `name` varchar(20) DEFAULT NULL, `account` bigint(20) DEFAULT NULL, `version` bigint(20) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; insert into `test_account`(`id`,`name`,`account`,`version`) values (1,'A',100,1); insert into `test_account`(`id`,`name`,`account`,`version`) values (2,'B',200,1); insert into `test_account`(`id`,`name`,`account`,`version`) values (3,'C',300,1);
. (1) Compatible en lecture et en lecture
Les verrous partagés sont compatibles avec les verrous partagés. Dans l'exemple suivant, session1 exécute la requête à t3 et session2 exécute la requête à t4 pour obtenir les résultats attendus :
( 2) Exclusion mutuelle en lecture et en écriture
Les verrous partagés et les verrous exclusifs s'excluent mutuellement. Dans l'exemple suivant, session1 ajoute un verrou partagé à l'instant t3, et le résultat peut être lu correctement, mais session2 essaie d'ajouter un verrou exclusif à l'instant t3. temps t4, mais le verrou est occupé par session1 à ce moment-là. Lorsque session1 ne libère pas le verrou pendant une longue période, session2 génère une exception de délai d'expiration de verrouillage :
(3) Write-write. exclusion mutuelle
Le verrouillage exclusif et le verrouillage exclusif s'excluent mutuellement, comme suit Dans l'exemple, session1 ajoute un verrou exclusif au temps t3, et le résultat peut être lu correctement, mais session2 essaie d'ajouter un verrou exclusif au temps t4, mais le verrou est occupé par session1 à ce moment-là, et session2 doit attendre. Lorsque session1 ne libère pas le verrou pendant une longue période, session2 Exception de délai d'attente de verrouillage levée :
Stockage MySQL Innodb. la mise en œuvre du moteur est basée sur le protocole de contrôle de concurrence multiversion MVCC. Dans le contrôle de concurrence MVCC, les opérations de lecture peuvent être divisées en lectures d'instantanés et lectures actuelles.
La lecture d'instantanés ne nécessite pas de verrouillage. Ce qui est lu est la version visible de l'enregistrement, qui peut être une version historique. Semblable à un instantané de commande, même si le prix du produit change après que l'utilisateur a passé la commande, l'instantané de commande reste inchangé. L'instruction de lecture actuelle est implémentée comme suit :
select
Afin de lire la dernière version de l'enregistrement sans être modifié par d'autres transactions, l'enregistrement actuel doit être verrouillé. L'implémentation de l'instruction de lecture actuelle est la suivante :
select lock in share mode select for update update delete insert
Nous analysons l'instantané lu et la lecture actuelle à travers un exemple. Session2 modifie l'enregistrement à t4 et le soumet à t5, effectue un instantané lu à t6 et lit le résultat. au début de cette transaction. 100. La lecture actuelle a été effectuée à l'instant t7, et la dernière version de l'enregistrement a été lue :
Comment se déroule le processus de lecture actuel ? Prenons la mise à jour comme exemple pour analyser le processus de lecture actuel :
La première fois que l'instance du programme émet la requête de lecture actuelle, le moteur de stockage renvoie le premier enregistrement qui répond à la condition Where et le verrouille, l'instance du programme émet une nouvelle demande de mise à jour, et le stockage provoque la réponse L'opération terminée a réussi. Exécutez dans l'ordre jusqu'à ce que tous les enregistrements qui satisfont à la condition Where soient exécutés.
Ici, nous réalisons quelques extensions. Le niveau RR fournit deux mécanismes pour éviter les problèmes de lecture fantôme : La première méthode est la lecture d'instantané, qui lit l'instantané lorsque la transaction en cours est démarrée. Une méthode pour les lectures en cours consiste à utiliser le mécanisme Next-Key Lock pour empêcher les lectures fantômes.
Nous intégrons les connaissances ci-dessus à travers une question : il y a deux threads exécutant les instructions suivantes en même temps. La valeur du compte de l'enregistrement avec id=1 sera-t-elle déduite avec succès deux fois ?
update test_account set account = account - 100, version = version + 1 where id = 1 and version = 1
La déclaration ci-dessus utilise le verrouillage optimiste. Nous savons que le verrouillage optimiste protège les ressources, donc la réponse est qu'il ne sera pas déduit deux fois, mais il ne peut pas s'arrêter là. Il doit être analysé plus en détail sur la base des connaissances du chapitre 1 :
A l'instant t2, session1 et session2 exécutent les opérations de mise à jour en même temps. Puisque la mise à jour ajoutera un verrou exclusif, un seul des deux peut réussir : session1 réussit et session2 bloque en attendant que le verrou exclusif soit libéré. .
Au moment t3, session1 valide la transaction et libère le verrou exclusif. À ce moment, session2 acquiert le verrou pour la lecture en cours, mais à ce moment, la valeur de version de l'enregistrement avec id=1 est passée à 2. L'instruction exécutée. ne peut pas interroger les données à mettre à jour, aucun enregistrement n'est donc renouvelé.
Si vous comprenez le principe de verrouillage optimiste du chapitre 2, le principe de déduction d'inventaire est déjà évident. Nous supposons qu'il ne reste qu'un seul article en stock si deux threads exécutent la déduction d'inventaire en même temps. temps, cela arrivera Situation de survente ?
Au temps t2, session1 et session2 exécutent updatek pour réduire l'inventaire en même temps. Puisque la mise à jour ajoutera un verrou exclusif, un seul des deux peut réussir : session1 réussit et session2 bloque en attendant le verrou exclusif. être libéré.
Au temps t3, la session1 valide la transaction et libère le verrou exclusif. A ce moment, la session2 obtient le verrou pour la lecture en cours, mais à ce moment, l'inventaire du produit 1 est devenu 0, et le (où stock - 1 >). ;= 0) la condition n'est plus remplie. Exécuter l'instruction. Les données à mettre à jour ne peuvent pas être interrogées, donc aucun enregistrement n'est mis à jour.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!