Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

Le texte est le suivant:

Comme nous le savons tous, les transactions et les verrous sont des fonctions très importantes dans mysql, et ils sont également au centre et à la difficulté des entretiens. Cet article présentera en détail les concepts associés de transactions et de verrous et leurs principes de mise en œuvre. Je pense qu'après l'avoir lu, vous aurez une meilleure compréhension des transactions et des verrous. Organisation d'un document MySQL, PDF de 328 pages

Qu'est-ce qu'une transaction

Dans Wikipédia, la définition d'une transaction est la suivante: une transaction est une unité logique dans l'exécution d'un système de gestion de base de données (SGBD), qui consiste en une séquence limitée d'opérations de base de données.

Quatre caractéristiques des transactions

La transaction contient quatre caractéristiques principales, à savoir l'atomicité, la cohérence, l'isolement et la durabilité (ACID).

  • Atomicité L'atomicité fait référence à une série d'opérations sur la base de données, soit toutes réussissent, soit toutes échouent. Un succès partiel est impossible. Prenons l'exemple du scénario de transfert. Le solde d'un compte diminue et le solde de l'autre compte augmente. Ces deux opérations doivent réussir ou échouer en même temps.

  • Cohérence (cohérence) La cohérence signifie que les contraintes d'intégrité de la base de données n'ont pas été détruites et qu'il s'agit d'un état de données légal avant et après l'exécution de la transaction. La cohérence ici peut signifier que les contraintes de la base de données elle-même n'ont pas été détruites, telles que les contraintes d'unicité de certains champs, les contraintes de longueur de champ, etc.; elle peut également indiquer des contraintes commerciales dans divers scénarios réels, comme l'opération de transfert ci-dessus , le montant d'argent réduit d'un compte Le montant ajouté à un autre compte doit être le même.

  • Isolation (Isolation) L'isolement signifie que plusieurs transactions sont complètement isolées les unes des autres et n'interfèrent pas les unes avec les autres. Le but ultime de l'isolement est également d'assurer la cohérence.

  • Durabilité La durabilité signifie que tant que la transaction est validée, les modifications apportées à la base de données sont enregistrées de façon permanente et il est impossible de revenir à l'état d'origine pour quelque raison que ce soit.

État de la transaction

Selon les différentes étapes du bureau, les affaires peuvent être grossièrement divisées en 5 états suivants:

  • Actif (actif) Lorsque l'opération de base de données correspondant à la transaction est en cours d'exécution, la transaction est active.

  • Partiellement validée (partiellement validée) Lorsque la dernière opération de la transaction est terminée, mais que les modifications n'ont pas été vidées sur le disque, la transaction est dans un état partiellement validée.

  • Échec (échec) Lorsque la transaction est active ou partiellement validée, la transaction ne peut pas être poursuivie en raison de certaines erreurs, la transaction est dans un état d'échec.

  • Abandonné (abandonné) Lorsque la transaction est dans un état d'échec, que l'opération d'annulation est terminée et que les données sont restaurées à l'état avant l'exécution de la transaction, la transaction est dans un état abandonné.

  • Soumise (validée) Lorsque la transaction est dans l'état partiellement validée et que les données modifiées sont synchronisées sur le disque, la transaction est dans l'état validée.

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

Niveau d'isolement des transactions

Comme mentionné précédemment, les transactions doivent être isolées. Le moyen le plus simple de réaliser l'isolation est de ne pas autoriser les transactions simultanées, et chaque transaction est mise en file d'attente pour exécution, mais les performances de cette méthode sont vraiment mauvaises. Afin d'équilibrer l'isolation et les performances de la transaction, la transaction prend en charge différents niveaux d'isolation.

Afin de faciliter la présentation du contenu suivant, nous créons d'abord un exemple de table hero.

CREATE TABLE hero (  
    number INT,  
    name VARCHAR(100),  
    country varchar(100),  
    PRIMARY KEY (number)  
) Engine=InnoDB CHARSET=utf8;

Problèmes rencontrés lors de l'exécution simultanée des transactions

Lorsque les transactions sont exécutées simultanément, si aucun contrôle n'est effectué, les quatre types de problèmes suivants peuvent survenir:

  • Écriture incorrecte (écriture incorrecte) L'écriture incorrecte fait référence à une transaction qui modifie les données non validées d'autres transactions.

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

Comme indiqué dans la figure ci-dessus, la session A et la session B démarrent chacune une transaction. La transaction de la session B met d'abord à jour la colonne de nom de l'enregistrement dont le numéro est répertorié comme 1 en "Guan Yu", puis la transaction de la session A puis répertorie le nombre comme La colonne de nom de l'enregistrement de 1 est mise à jour vers Zhang Fei. Si la transaction de la session B est annulée ultérieurement, la mise à jour de la session A n'existera plus. Ce phénomène est appelé écriture incorrecte.

  • Lecture sale La lecture sale fait référence à une transaction qui lit des données non validées à partir d'autres transactions.

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?
Comme le montre la figure ci-dessus, la session A et la session B démarrent chacune une transaction. La transaction de la session B met d'abord à jour la colonne de nom de l'enregistrement dont le numéro est répertorié comme 1 en "Guan Yu", puis la transaction dans les requêtes de la session A le nombre est égal à 1 Si la valeur du nom de la colonne est "Guan Yu" et que la transaction de la session B est annulée ultérieurement, la transaction de la session A équivaut à la lecture d'une donnée inexistante. Ce phénomène est appelé Read for dirty .

  • Lecture non répétable La lecture non répétable fait référence aux données qui ont été soumises par d'autres transactions et sont lues pendant l'exécution d'une transaction, ce qui entraîne des résultats incohérents des deux lectures.

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

Comme le montre la figure ci-dessus, nous avons soumis plusieurs transactions implicites dans la session B (mysql ajoutera automatiquement des transactions pour les instructions d'ajout, de suppression et de modification). Ces transactions ont modifié la valeur du nom de colonne de l'enregistrement dont la colonne numéro est 1 Une fois que chaque transaction est validée, si toutes les transactions de la session A peuvent afficher la dernière valeur, ce phénomène est également appelé lecture non répétable.

  • Phantom Phantom signifie que lors de l'exécution d'une transaction, les données nouvellement insérées des autres transactions sont lues, ce qui entraîne des résultats incohérents des deux lectures.

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

Comme le montre la figure ci-dessus, la transaction de la session A interroge d'abord le héros de la table en fonction du numéro de condition> 0, et obtient l'enregistrement avec la valeur de colonne de nom `` Liu Bei ''; puis une transaction implicite est soumise dans la session B, et la transaction est insérée dans le héros de la table Un nouvel enregistrement est créé; après cela, la transaction dans la session A interroge le héros de la table selon le même numéro de condition> 0, et le jeu de résultats contient l'enregistrement nouvellement inséré de la transaction dans la session B. Ce phénomène est également appelé lecture fantôme.

La différence entre la lecture non répétable et la lecture fantôme est que la lecture non répétable lit les données modifiées ou supprimées par d'autres transactions, tandis que la lecture fantôme lit les données nouvellement insérées par d'autres transactions.

Le problème de l'écriture sale est trop grave et tout niveau d'isolement doit être évité. Qu'il s'agisse d'une lecture sale, d'une lecture non répétable ou d'une lecture fantôme, elles appartiennent toutes au problème de la cohérence de lecture de la base de données, et elles sont incohérentes entre deux lectures dans une transaction.

Quatre niveaux d'isolement

Quatre niveaux d'isolement sont établis dans la norme SQL pour résoudre le problème de cohérence de lecture ci-dessus. Différents niveaux d'isolement peuvent résoudre différents problèmes de cohérence de lecture.

  • READ UNCOMMITTED: lecture non validée.

  • READ COMMITTED: a été soumis pour lecture.

  • REPEATABLE READ: lecture répétable.

  • SERIALIZABLE: sérialisation.

Les problèmes de cohérence de lecture possibles sous chaque niveau d'isolement sont les suivants:

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

InnoDB prend en charge quatre niveaux d'isolement (essentiellement cohérents avec la définition du standard SQL). Plus le niveau d'isolement est élevé, plus la concurrence des transactions est faible. La seule différence est qu'InnoDB résout le problème des lectures fantômes au niveau REPEATABLE READ. C'est pourquoi InnoDB utilise la lecture répétable comme niveau d'isolement par défaut pour les transactions.

MVCC

MVCC (Multi Version Concurrency Control), le nom chinois est le contrôle de concurrence multi-version. En termes simples, il résout le problème de la cohérence de lecture en accès simultané en conservant la version historique des données.

Chaîne de version

Dans InnoDB, chaque ligne d'enregistrements contient en fait deux champs cachés: l'identifiant de transaction (trx_id) et le pointeur de retour arrière (roll_pointer).

  1. trx_id: identifiant de transaction. Chaque fois qu'une ligne est modifiée, l'identifiant de transaction de la transaction sera attribué à la colonne cachée trx_id.

  2. roll_pointer: pointeur de retour arrière. Chaque fois qu'une ligne est modifiée, l'adresse du journal d'annulation est affectée à la colonne masquée de roll_pointer.

Supposons qu'il n'y ait qu'une seule ligne dans la table des héros et que l'ID de transaction inséré à ce moment-là soit 80. À ce stade, l'exemple de diagramme de l'enregistrement est le suivant:

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

En supposant que deux transactions avec des ID de transaction de 100 et 200 exécutent une opération UPDATE sur cet enregistrement, le déroulement des opérations est le suivant:

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

Parce que chaque modification sera d'abord enregistrée dans le journal d'annulation et utilisez roll_pointer pour pointer vers l'adresse du journal d'annulation. Par conséquent, on peut considérer que le journal des modifications de cet enregistrement est connecté en série pour former une chaîne de versions, et le nœud principal de la chaîne de versions est la dernière valeur de l'enregistrement actuel. comme suit:
Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

ReadView

Si le niveau d'isolement de la base de données est READ UNCOMMITTED, l'enregistrement de la dernière version de la chaîne de versions peut être lu. S'il est sérialisé (SERIALIZABLE), les transactions sont exécutées avec des verrous, et il n'y a pas de problème d'incohérence de lecture. Mais s'il est READ COMMITTED ou REPEATABLE READ, il est nécessaire de parcourir chaque enregistrement de la chaîne de version pour déterminer si l'enregistrement est visible par la transaction en cours jusqu'à ce qu'il soit trouvé (s'il n'est pas trouvé une fois la traversée terminée). l'enregistrement n'existe pas). InnoDB implémente cette fonction via ReadView. ReadView contient principalement les 4 contenus suivants:

  • m_ids: représente une liste d'identifiants de transaction des transactions de lecture et d'écriture actives dans le système actuel lorsque ReadView est généré.

  • min_trx_id: représente le plus petit identifiant de transaction parmi les transactions de lecture et d'écriture actives dans le système actuel lorsque le ReadView est généré, c'est-à-dire la plus petite valeur de m_ids.

  • max_trx_id: indique la valeur d'id qui doit être affectée à la prochaine transaction dans le système lorsque le ReadView est généré.

  • creator_trx_id: représente l'ID de transaction qui a généré la transaction ReadView.

Avec ReadView, nous pouvons juger si une certaine version de l'enregistrement est visible pour la transaction actuelle en fonction des étapes suivantes.

  • Si la valeur de l'attribut trx_id de la version accédée est la même que la valeur creator_trx_id dans ReadView, cela signifie que la transaction actuelle accède à son propre enregistrement modifié, de sorte que cette version est accessible par la transaction actuelle.

  • Si la valeur de l'attribut trx_id de la version accédée est inférieure à la valeur min_trx_id dans ReadView, cela indique que la transaction qui a généré cette version a été validée avant que la transaction actuelle ne génère ReadView, cette version est donc accessible par la transaction actuelle.

  • Si la valeur d'attribut trx_id de la version accédée est supérieure ou égale à la valeur max_trx_id dans ReadView, cela indique que la transaction qui a généré cette version est démarrée après que la transaction actuelle génère ReadView, de sorte que cette version ne peut pas être accédée par la transaction actuelle.

  • Si la valeur de l'attribut trx_id de la version accédée se situe entre min_trx_id et max_trx_id de ReadView, vous devez déterminer si la valeur d'attribut trx_id se trouve dans la liste m_ids. Si tel est le cas, cela signifie que la transaction qui a généré cette version lorsque ReadView a été créée est toujours active. Accessible. Si ce n'est pas le cas, cela signifie que la transaction qui a généré la version lors de la création de ReadView a été validée et que la version est accessible.

Dans MySQL, une très grande différence entre les niveaux d'isolement READ COMMITTED et REPEATABLE READ est qu'ils génèrent ReadView à des moments différents. READ COMMITTED génère un ReadView à chaque fois avant de lire les données, afin de garantir que les données soumises par d'autres transactions peuvent être lues à chaque fois. REPEATABLE READ génère un ReadView uniquement lorsque les données sont lues pour la première fois, afin de garantir que les résultats des lectures suivantes sont parfaitement cohérents.

fermer à clé

L'accès simultané à la même ressource de données par les transactions est principalement divisé en trois types: lecture-lecture, écriture-écriture et lecture-écriture.

  • Lecture-lecture signifie que les transactions simultanées accèdent simultanément à la même ligne d'enregistrements de données. Étant donné que les deux transactions effectuent des opérations en lecture seule et n'entraîneront aucun impact sur l'enregistrement, les lectures simultanées sont totalement autorisées.

  • L'écriture-écriture signifie que les transactions simultanées modifient la même ligne d'enregistrements de données en même temps. Cette situation peut entraîner des problèmes d'écriture incorrecte, ce qui n'est autorisé en aucun cas, donc cela ne peut être réalisé que par verrouillage, c'est-à-dire que lorsqu'une transaction doit modifier une ligne d'enregistrements, elle donnera d'abord ce verrou d'enregistrement, si le le verrouillage est réussi, continuez l'exécution, sinon attendez en ligne, l'exécution de la transaction est terminée ou annulée libère automatiquement le verrou.

  • La lecture-écriture signifie qu'une transaction effectue une opération de lecture et l'autre exécute une opération d'écriture. Dans ce cas, des lectures incorrectes, des lectures non répétables et des lectures fantômes peuvent se produire. La meilleure solution consiste à utiliser le contrôle d'accès concurrentiel multi-version (MVCC) pour les opérations de lecture et le verrouillage pour les opérations d'écriture.

Verrouiller la granularité

Selon la plage de données de la fonction de verrouillage, les verrous peuvent être divisés en verrous de niveau ligne et verrous de niveau table.

  1. Verrou au niveau de la ligne: Agissez sur la ligne de données, la granularité du verrou est relativement faible.

  2. Verrou au niveau de la table: en agissant sur l'ensemble de la table de données, la granularité du verrou est relativement grande.

Classification des serrures

Afin de réaliser que la lecture-lecture n'est pas affectée et que l'écriture-écriture et la lecture-écriture peuvent se bloquer mutuellement, Mysql utilise l'idée de lire et d'écrire des verrous pour le réaliser, en particulier il est divisé en verrous partagés et serrures exclusives:

1. Verrous partagés (verrous partagés): appelés verrous S. Lorsqu'une transaction souhaite lire un enregistrement, le verrou S de l'enregistrement doit d'abord être acquis. Les verrous S peuvent être détenus par plusieurs transactions en même temps. Nous pouvons utiliser select ...... lock en mode partage; pour ajouter manuellement un verrou S.

2. Verrous exclusifs (verrous exclusifs): appelés verrous X, lorsqu'une transaction souhaite modifier un enregistrement, le verrou X de l'enregistrement doit d'abord être acquis. Les verrous X ne peuvent être détenus que par une seule transaction à la fois. Il existe deux façons de verrouiller les verrous X. Le premier est le verrouillage automatique. Lors de l'ajout, de la suppression ou de la modification de données, un verrou X est ajouté par défaut. Il existe également un verrou manuel. Nous utilisons un FOR UPDATE pour ajouter un verrou X à une ligne de données.

Une autre chose à noter est que si une transaction détient déjà un verrou S pour une ligne d'enregistrements, une autre transaction ne peut pas ajouter un verrou X pour cette ligne, et vice versa.

En plus des verrous partagés (Shared Locks) et des verrous exclusifs (Exclusive Locks), Mysql dispose également de verrous d'intention (Intention Locks). Le verrou d'intention est conservé par la base de données elle-même. En règle générale, avant d'ajouter un verrou partagé à une ligne de données, la base de données ajoute automatiquement un verrou partagé d'intention (verrou IS) à cette table; lorsque nous ajoutons un verrou exclusif à un rangée de données Avant le verrouillage, la base de données ajoutera automatiquement un verrou exclusif d'intention (verrou IX) à cette table. Le verrou d'intention peut être considéré comme l'identification du verrou S et du verrou X sur la table de données. Grâce au verrou d'intention, vous pouvez rapidement déterminer si un enregistrement de la table est verrouillé, afin d'éviter de parcourir pour voir s'il y a un enregistrement dans la table verrouillée Efficacité du verrouillage. Par exemple, si nous voulons ajouter des verrous X au niveau de la table, s'il existe des verrous X au niveau de la ligne ou des verrous S dans la table de données, le verrou échouera. À ce stade, nous pouvons savoir si cette table a un niveau de ligne directement basé sur le verrou d'intention. Verrou X ou verrou S.

Verrous au niveau de la table dans InnoDB

Les verrous au niveau de la table dans InnoDB incluent principalement les verrous partagés d'intention au niveau de la table (verrous IS) et les verrous exclusifs d'intention (verrous IX) et les verrous auto-croissants (verrous AUTO-INC). Parmi eux, le verrouillage IS et le verrouillage IX ont déjà été introduits, donc je ne les répéterai pas ici.

Tout le monde sait que si nous ajoutons l'attribut AUTO_INCREMENT à un champ de colonne, il n'est pas nécessaire de spécifier une valeur pour le champ lors de l'insertion, et le système garantira automatiquement l'incrément. Il existe deux principes principaux pour que le système réalise cette affectation incrémentielle automatique aux colonnes modifiées AUTO_INCREMENT:

1. Verrou AUTO-INC: Le verrou AUTO-INC au niveau de la table est ajouté lorsque l'instruction d'insertion est exécutée, et le verrou est libéré immédiatement après l'exécution de l'insertion. Si nous ne pouvons pas déterminer le nombre d'enregistrements à insérer avant l'exécution de notre instruction insert, comme les instructions INSERT ... SELECT insert, utilisez généralement la méthode de verrouillage AUTO-INC.

2. Verrou léger: le verrou léger est acquis en premier lorsque la valeur AUTO_INCREMENT est générée par l'instruction d'insertion, puis le verrou léger est libéré après la génération de la valeur AUTO_INCREMENT. Si notre instruction d'insertion peut déterminer le nombre d'enregistrements à insérer avant son exécution, un verrou léger est généralement utilisé pour affecter des valeurs aux colonnes modifiées par AUTO_INCREMENT. Cette approche peut éviter de verrouiller la table et peut améliorer les performances de l'insert.

"Par défaut, MySQL sélectionne automatiquement le mode de verrouillage en fonction du scénario réel. Bien sûr, vous pouvez également forcer innodb_autoinc_lock_mode à spécifier un seul d'entre eux."

Verrous au niveau des lignes dans InnoDB

Comme mentionné précédemment, MVCC peut résoudre les problèmes de cohérence de lecture des lectures sales, des lectures non répétables et des lectures fantômes, mais en fait, cela ne résout que le problème de lecture de données des instructions SELECT ordinaires. L'opération de lecture effectuée par la transaction à l'aide de MVCC est appelée lecture d'instantané, et toutes les instructions SELECT ordinaires sont considérées comme une lecture d'instantané sous les niveaux d'isolement READ COMMITTED et REPEATABLE READ. En plus des lectures instantanées, il existe également une lecture verrouillée, c'est-à-dire verrouiller l'enregistrement pendant la lecture, et il faut encore résoudre les problèmes de lecture sale, de lecture non répétable et de lecture fantôme dans le cas d'une lecture verrouillée. Étant donné que tous les verrous sont placés sur les enregistrements, ces verrous sont tous des verrous de niveau ligne.

Le verrouillage des lignes d'InnoDB est obtenu en verrouillant l'index. Si l'index n'est pas utilisé lors du verrouillage de la requête, tout l'index clusterisé sera verrouillé, ce qui équivaut au verrouillage de la table. Selon les différentes plages de verrouillage, les verrous de ligne peuvent être réalisés en utilisant des verrous d'enregistrement, des verrous d'espacement et des verrous à clé suivante. Supposons qu'il existe une table t et que la clé primaire est id. Nous avons inséré 4 lignes de données, les valeurs de clé primaire sont 1, 4, 7 et 10. Ensuite, nous prendrons l'index clusterisé comme exemple pour introduire spécifiquement trois formes de verrous de ligne.

  • Verrouillages d'enregistrement Les soi-disant enregistrements font référence aux données réellement stockées dans l'index groupé. Par exemple, 1, 4, 7 et 10 ci-dessus sont tous des enregistrements.

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

De toute évidence, le verrouillage d'enregistrement consiste à verrouiller directement une ligne d'enregistrements. Lorsque nous utilisons un index unique (comprenant un index unique et un index clusterisé) pour effectuer une requête équivalente et correspondre exactement à un enregistrement, l'enregistrement sera directement verrouillé à ce moment. Par exemple, sélectionnez * à partir de t où id = 4 pour la mise à jour; verrouillera l'enregistrement avec id = 4.

  • Gap Locks Gap fait référence à la partie entre deux enregistrements qui n'a pas été remplie de données logiquement, comme ci-dessus (1,4), (4,7), etc.

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

De la même manière, le verrouillage d'écart consiste à verrouiller certains intervalles d'intervalle. Lorsque nous utilisons une requête d'équivalence ou une requête de plage et que nous n'atteignons aucun enregistrement, l'intervalle d'intervalle correspondant sera verrouillé. Par exemple, sélectionnez à partir de t où id = 3 pour la mise à jour; ou sélectionnez à partir de t où id> 1 et id <4 pour la mise à jour; verrouillera l'intervalle (1,4).

  • Verrous de clé suivante (Verrous de clé suivante) Les verrous de clé suivante font référence à l'intervalle d'ouverture gauche et de fermeture droite composé de l'espace plus l'enregistrement à sa droite. Par exemple, ce qui précède (1,4], (4,7), etc.

Momo Interviewer: Parlez-moi de votre compréhension des transactions et des verrous dans MySQL?

Le verrouillage des touches adjacent est une combinaison de verrous d'enregistrement et de verrouillage d'espacement, c'est-à-dire qu'en plus de verrouiller l'enregistrement lui-même, il verrouille également l'espace entre les index. Lorsque nous utilisons une requête de plage et atteignons une partie de l'enregistrement, la plage de clés est verrouillée à ce moment. Notez que l'intervalle verrouillé par le verrouillage de la clé de proximité comprendra l'intervalle de la clé de proximité à droite du dernier enregistrement. Par exemple, sélectionnez * from t où id> 5 et id <= 7 pour la mise à jour; verrouillera (4,7], (7, + ∞). Le type de verrouillage de ligne par défaut de mysql est Next-Key Locks. Utilisation d'un unique index, lorsqu'une requête équivalente correspond à un enregistrement, les verrous de clé suivante dégénèrent en un verrou d'enregistrement; lorsqu'aucun enregistrement ne correspond, il dégénère en un verrou d'intervalle.

Les verrous d'espacement et les verrous à clé suivante sont tous deux utilisés pour résoudre le problème de la lecture fantôme. Sous le niveau d'isolement READ COMMITTED, les verrous d'espacement et les verrous de clé suivante (verrous de clé) échoueront! Organisation d'un document MySQL, PDF de 328 pages

Je suppose que tu aimes

Origine blog.51cto.com/14975073/2608574
conseillé
Classement