Dans la base de données MySQL, la différence entre la lecture fantôme sous deux niveaux d'isolation de transaction différents : lecture validée et lecture répétable

1. Introduction

Avant de commencer officiellement, passons brièvement en revue les problèmes de transactions concurrentes et le niveau d'isolement des transactions.

1.1 Problèmes avec les transactions simultanées

Lorsque deux transactions ou plus sont ouvertes en même temps pour traiter les données de la même table, les problèmes suivants peuvent survenir :

  • modification perdue
  • lecture sale
  • lecture non répétable
  • Lecture fantôme

modification perdue

La modification perdue fait référence au phénomène selon lequel lorsque deux transactions ou plus mettent à jour la même ligne d'enregistrements, la mise à jour est perdue. La couverture d'annulation de transaction et la couverture de validation de transaction provoquent ce phénomène.

lecture sale

Une transaction peut lire des données qui ont été modifiées par une autre transaction mais pas encore validées.

lecture non répétable

Si la même instruction de requête est exécutée plusieurs fois dans une transaction, le contenu des données lues est incohérent.

Lecture fantôme

Si la même instruction de requête est exécutée plusieurs fois dans une transaction, le nombre d'enregistrements de données lus est incohérent et il peut y avoir quelques enregistrements de plus ou quelques enregistrements de moins.

1.2 Niveau d'isolation des transactions

Afin de résoudre les problèmes de transactions concurrentes, les patrons ont pensé à une méthode, qui consiste à isoler les transactions. Il est préférable de faire fonctionner chaque transaction indépendamment sans interférer les unes avec les autres, mais l'idéal est très complet, et la réalité est très maigre. Cela peut être fait en une seule étape.

Afin de répondre à différents besoins et de résoudre différents problèmes, il a été décidé de diviser l'isolement des transactions en quatre niveaux, à savoir :

  • lecture non validée
  • lire engagé
  • lecture répétable
  • Sérialisation

Les problèmes de transactions simultanées qu'ils peuvent résoudre respectivement sont présentés dans le tableau suivant :

Niveau d'isolement\Problèmes de transaction remplacement de l'annulation de la transaction lecture sale lecture non répétable remplacement de validation de transaction Lecture fantôme
lecture non validée peut résoudre ne peut pas résoudre ne peut pas résoudre ne peut pas résoudre ne peut pas résoudre
lire engagé peut résoudre peut résoudre ne peut pas résoudre ne peut pas résoudre ne peut pas résoudre
lecture répétable peut résoudre peut résoudre peut résoudre peut résoudre ne peut pas être entièrement résolu, peut se produire
Sérialisation peut résoudre peut résoudre peut résoudre peut résoudre peut résoudre

1.3 Instantané lu et lecture actuelle

instantané lu

La lecture d'instantané est implémentée sur la base du MVCC et du journal d'annulation. Elle lit la version historique des données et obtient une ReadView (vue transactionnelle). Elle ne verrouille pas les données et convient aux selectdéclarations

Permettez-moi de mentionner ici que le soi-disant contrôle de version simultané MVCC est réalisé par ReadView (vue de transaction), et plusieurs readViews forment un journal d'annulation (journal de restauration).

en train de lire

La lecture actuelle est implémentée sur la base du verrouillage de ligne + verrouillage d'espace, lit la dernière version des données et verrouille les données, ce qui est applicable insert,update,delete, select ... for update, select ... lock in share mode 语句,以及加锁了的 select 语句.

Lors de la mise à jour des données, elles sont toujours lues en premier, puis écrites, et cette lecture fait référence à la lecture actuelle, ce qui signifie que lors de la lecture des données, ce qui est lu est le dernier ReadView généré par les données.

2. La différence entre la lecture fantôme sous différents niveaux d'isolement des transactions

Dans le tableau ci-dessus, nous pouvons voir que sous le niveau d'isolement de lecture validée, la lecture fantôme ne peut pas être résolue, c'est-à-dire qu'elle se produira ; tandis que sous le niveau d'isolement de lecture répétable, la lecture fantôme n'est pas complètement bloquée. que partiellement résolu, cela signifie que cela peut encore arriver.

Comment sont-ils arrivés? Quelles sont leurs performances ? Quelle est la différence? Prenons un exemple à explorer.

En supposant qu'il y ait deux transactions, à savoir la transaction A et la transaction B, et une table étudiant étudiant (il n'y a qu'un seul enregistrement dans la table, stu_name est Wang Da), nous utilisons ces deux transactions pour faire fonctionner cette table.

2.1 Lecture fantôme sous read commit

Sous le niveau d'isolement de transaction de lecture validée, l'ordre des opérations des deux transactions est le suivant :

Opération A Opération B
commencer;
commencer;
Lancez la première requête : sélectionnez * de l'étudiant où stu_id > 0 ;
insert into student(stu_name) values('李二');
commettre;
Lancez la deuxième requête : sélectionnez * de l'étudiant où stu_id > 0 ;
  1. Dans la première requête de la transaction A, l'enregistrement de données obtenu est stu_name as Wang Da
  2. La transaction B insère un enregistrement dont stu_name est Li Er dans la table à mi-chemin et soumet sa propre transaction
  3. Lorsque la transaction A utilise l'instruction SQL de la première requête pour effectuer la deuxième requête, il s'avère que les enregistrements de données obtenus sont au nombre de deux et une lecture fantôme se produit

Performance

Pour les instructions de requête ordinaires, un phénomène de lecture fantôme évident peut être observé.

Analyse des causes

L'instruction select ordinaire est utilisée dans la transaction A, donc la lecture d'instantané est utilisée, mais comme le niveau d'isolement de la transaction est validé en lecture, c'est pour cette raison que les résultats obtenus 在读已提交下,每次 select 操作,都会重新获取最新版本的数据par les deux requêtes dans la transaction A sont incohérents en quantité, Lecture fantôme se produit.

solution

Mettre à niveau le niveau d'isolement des transactions vers une lecture répétable

2.2 Lecture fantôme sous lecture répétable

2.2.1 Cas 1, pas de lecture fantôme

Sous le niveau d'isolement de transaction de lecture répétable, la séquence d'opérations de deux transactions est la suivante :

Opération A Opération B
commencer;
commencer;
Lancez la première requête : sélectionnez * de l'étudiant où stu_id > 0 ;
insert into student(stu_name) values('李二');
commettre;
Lancez la deuxième requête : sélectionnez * de l'étudiant où stu_id > 0 ;

Pour les opérations de transaction comme ci-dessus, bien que la lecture fantôme se produira sous le niveau d'isolement de transaction de lecture validée, la lecture fantôme ne se produira pas sous le niveau d'isolement de transaction de lecture répétable.

Raison : 在可重复读事务隔离级别下,针对普通的 select 语句,采用的是快照读,只会在第一次查询的时候获取一次数据的版本,往后继续做相同的 select 操作,不会重新获取,会延用前面得到的数据版本.

Attention, avez-vous remarqué que sous le niveau d'isolement des transactions de lecture répétable, pour la lecture d'instantané (opération de sélection ordinaire), n'est-ce pas simplement utiliser MVCC pour résoudre le problème de lecture fantôme? Vous avez bien lu, ça l'est.

2.2.2 Cas 2, lecture fantôme

Sous le niveau d'isolement de transaction de lecture répétable, la séquence d'opérations de deux transactions est la suivante :

Opération A Opération B
commencer;
commencer;
Lancez la première requête : sélectionnez * de l'étudiant où stu_id > 0 ;
insert into student(stu_name) values('李二');
commettre;
Lancez la deuxième requête : sélectionnez * de l'étudiant où stu_id > 0 pour la mise à jour ;

L'opération de transaction ci-dessus est différente de la précédente en ce que la deuxième requête ajoute pour la mise à jour, c'est-à-dire que la lecture actuelle est utilisée.

Performance

Peut voir un phénomène de lecture fantôme évident

Analyse des causes

Comme la deuxième requête de la transaction A ajoute for update à la fin de l'instruction SQL, indiquant que la méthode de lecture courante est utilisée pour obtenir la dernière version des données, les données insérées au milieu de la transaction B seront naturellement découvertes, entraînant une lecture fantôme.

solution

Utilisez le verrou de touche suivante pour le résoudre. Si vous utilisez l'index, il verrouillera le verrou de ligne de l'index lui-même ; s'il s'agit d'une plage, il deviendra un verrou de ligne + un verrou d'espace, ce qui rendra impossible l'insertion dans la plage ; s'il n'y a pas d'index, directement tous La table a un verrou d'espacement, qui ne peut pas être inséré et bloqué.

La méthode de fonctionnement spécifique est la suivante :

Opération A Opération B
commencer;
commencer;
Lancez la première requête : sélectionnez * de l'étudiant où stu_id > 0 pour la mise à jour ;
insert into student(stu_name) values('李二');
commettre;
Lancez la deuxième requête : sélectionnez * de l'étudiant où stu_id > 0 pour la mise à jour ;

La mise à jour est ajoutée à chaque requête de la transaction A, de sorte que la lecture fantôme ne se produira pas, car l'opération d'insertion de la transaction B sera bloquée et les données ne pourront pas être insérées dans la table, évitant ainsi l'occurrence de la lecture fantôme.

2.2.3 Cas 3, lecture fantôme

Sous le niveau d'isolement de transaction de lecture répétable, la séquence d'opérations de deux transactions est la suivante :

Opération A Opération B
commencer;
commencer;
Lancez la première requête : sélectionnez * de l'étudiant où stu_id > 0 ;
insert into student(stu_name) values('李二');
commettre;
update student set stu_class = ‘03’ where stu_id is not null;
开始第二次查询:select * from student where stu_id > 0;

在上面的事务操作下,事务 B 能将数据记录正常插入到表中,而事务 A 做了一次 update 操作,从上面的介绍我们可以知道,update 操作是当前读,会获取到数据的最新版本,自然也能拿到事务 B 的提交记录。

表现

能明显看到幻读现象

原因剖析

事务 A 的 update 操作采用的是当前读,会获取数据的最新版本,将事务 B 提交的结果读取出来,后面事务 A 再做普通的 select 操作,采用快照读,由于延用 update 操作时得到的数据历史版本,因而产生幻读。

解决方式

同 2.2.2 中的解决方式一样,具体操作如下:

事务A 事务B
begin;
begin;
开始第一次查询:select * from student where stu_id > 0 for update;
insert into student(stu_name) values(‘李二’);
commit;
update student set stu_class = ‘03’ where stu_id is not null;
开始第二次查询:select * from student where stu_id > 0 for update;

最简单的解决方式,就是再将事务隔离级别升级,改为串行化,毕竟串行化本身就解决所有事务问题,当然,这会牺牲效率。

3. 小 结

  1. 并发事务中,对于普通的 select 语句,在读已提交下,能明显看到幻读的现象,而在可重复读下,看不到幻读现象。
  2. 并发事务中,对于事务执行语句里含有当前读的情况,得具体问题具体分析,可能可以看到幻读,也可能由于加了 for update ,看不到幻读。

Je suppose que tu aimes

Origine blog.csdn.net/Crezfikbd/article/details/130446725
conseillé
Classement