Série Fun with Mysql - Partie 14 : Explication détaillée des transactions

Environnement : mysql5.7.25, démontré dans la commande cmd.

Les transactions de base de données sont souvent utilisées pendant le processus de développement, ce chapitre est donc très important.

Contenu de cet article

  1. Qu'est-ce qu'une transaction et à quoi sert-elle ?

  2. Plusieurs caractéristiques des transactions

  3. Explication détaillée des instructions d'opération de transaction courantes

  4. Explication détaillée du niveau d'isolement des transactions

  5. Lecture sale, lecture non répétable, lecture répétable, lecture fantôme en détail

  6. Démontrer les phénomènes produits par différents niveaux d’isolement

  7. Concernant le choix du niveau d’isolement

Qu'est-ce qu'une transaction ?

Une transaction dans une base de données fait référence à l'exécution d'un lot d'opérations sur la base de données. Ces opérations finiront par réussir ou échouer, et il n'y aura pas de succès partiel.

Par exemple

Par exemple, si l'utilisateur A transfère 100 à l'utilisateur B, le processus est le suivant :

1.从A账户扣100
2.给B账户加100

Avec le support des transactions, il n'y a que deux résultats ci-dessus :

  1. Opération réussie : le compte A diminue de 100 ; le compte B augmente de 100

  2. L'opération a échoué : ni le compte A ni le compte B n'ont changé.

S'il n'y a pas de support de transaction, une erreur peut se produire : le compte A est réduit de 100 et le système raccroche. Par conséquent, le compte B n'ajoute pas 100 et le compte A en perd 100 à partir de rien.

Plusieurs caractéristiques des transactions (ACID)

Atomicité

L'ensemble du processus d'une transaction est comme une opération atomique. En fin de compte, soit tous réussissent, soit tous échouent. Cette atomicité se voit à partir du résultat final. À partir du résultat final, ce processus est indivisible.

Cohérence

Avant le début de la transaction, pendant l'exécution et après l'exécution, à ces moments-là, lorsque plusieurs personnes observent les données de l'opération de transaction, les données qu'elles voient sont cohérentes. Par exemple, pendant l'opération de transaction, la connexion A voit 100, puis Lorsque B l'a également regardé à ce moment-là, c'était également 100. On ne dirait pas que les données vues par AB étaient différentes. Les données qu'ils ont vues à un certain moment étaient cohérentes.

Isolement

L'exécution d'une transaction ne peut être perturbée par d'autres transactions. Autrement dit, les opérations et les données utilisées dans une transaction sont isolées des autres transactions simultanées et les transactions exécutées simultanément ne peuvent pas interférer les unes avec les autres.

Durabilité

Une fois qu'une transaction est validée, ses modifications apportées aux données de la base de données doivent être permanentes. Lorsque la transaction est validée, les données seront conservées sur le disque dur et la modification sera permanente.

Opérations de transaction dans MySQL

Les transactions dans MySQL sont des transactions implicites par défaut. Lors de l'exécution d'opérations d'insertion, de mise à jour et de suppression, la base de données démarre, valide ou annule automatiquement les transactions.

L'activation ou non des transactions implicites est autocommitcontrôlée par des variables.

Les transactions sont donc divisées en transactions implicites et transactions explicites .

transaction implicite

Les transactions sont automatiquement ouvertes, soumises ou annulées, telles que les instructions d'insertion, de mise à jour, de suppression. L'ouverture, la soumission ou l'annulation des transactions sont automatiquement contrôlées en interne par MySQL.

Vérifiez autocommitsi la soumission automatique de la variable est activée

mysql> show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+
1 row in set, 1 warning (0.00 sec)

autocommitON signifie que la soumission automatique est activée.

transaction explicite

Les transactions doivent être démarrées, validées ou annulées manuellement, ce qui est contrôlé par le développeur.

2 façons de contrôler manuellement les transactions :

Voie 1 :

grammaire:

//设置不自动提交事务
set autocommit=0;
//执行事务操作
commit|rollback;

Exemple 1 : Soumettez l'opération de transaction, comme suit :

mysql> create table test1 (a int);
Query OK, 0 rows affected (0.01 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values(1);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

Exemple 2 : opération de transaction de restauration, comme suit :

mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values(2);
Query OK, 1 row affected (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

Vous pouvez voir que les données ci-dessus ont été restaurées.

Restaurons-leautocommit :

mysql> set autocommit=1;
Query OK, 0 rows affected (0.00 sec)

Voie 2 :

grammaire:

start transaction;//开启事务
//执行事务操作
commit|rollback;

Exemple 1 : Soumettez l'opération de transaction, comme suit :

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (2);
Query OK, 1 row affected (0.00 sec)

mysql> insert into test1 values (3);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

Deux éléments de données ont été insérés avec succès ci-dessus.

Exemple 2 : opération de transaction de restauration, comme suit :

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from test1;
Query OK, 3 rows affected (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

Les données que nous avons supprimées dans la transaction ci-dessus test1montrent que 3 lignes ont été supprimées et que la transaction a finalement été annulée.

mot-clé de point de sauvegarde

Nous avons effectué un grand nombre d'opérations au cours de la transaction. Peut-être souhaitons-nous simplement restaurer certaines données. Comment faire ?

Nous pouvons diviser un grand nombre d'opérations en plusieurs parties, puis spécifier d'annuler une certaine partie. savepoinCeci peut être réalisé en utilisant :

Effacez d’abord test1les données du tableau :

mysql> delete from test1;
Query OK, 3 rows affected (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

Effet de démonstration savepoint, regardez attentivement :

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (1);
Query OK, 1 row affected (0.00 sec)

mysql> savepoint part1;//设置一个保存点
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (2);
Query OK, 1 row affected (0.00 sec)

mysql> rollback to part1;//将savepint = part1的语句到当前语句之间所有的操作回滚
Query OK, 0 rows affected (0.00 sec)

mysql> commit;//提交事务
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

Comme le montre ce qui précède, 2 opérations d'insertion sont effectuées et une seule donnée est insérée à la fin.

savepointIl doit être utilisé en combinaison pour annuler les opérations entre le point de sauvegarde et rollback to sp1le point de sauvegarde .sp1rollback to

transaction en lecture seule

Cela signifie que certaines opérations en lecture seule, telles que les requêtes, sont effectuées dans la transaction, mais que les opérations d'insertion, de mise à jour et de suppression ne seront pas effectuées. Il peut y avoir certaines optimisations de performances pour les transactions en lecture seule au sein de la base de données.

L'utilisation est la suivante :

start transaction read only;

Exemple:

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> start transaction read only;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    1 |
+------+
2 rows in set (0.00 sec)

mysql> delete from test1;
ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.
mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    1 |
+------+
2 rows in set (0.00 sec)

L’exécution de delete dans une transaction en lecture seule signalera une erreur.

Quelques problèmes dans la transaction

Ces problèmes reposent principalement sur la visibilité des données sur plusieurs transactions.

sale lecture

Une transaction lit les données qui n'ont pas été validées par d'autres transactions lors de l'exécution.
Cela reste relativement facile à comprendre.

lire engagé

Littéralement, nous pouvons comprendre que lors d'une opération de transaction, les données soumises par d'autres transactions peuvent être lues.

Chaque opération de lecture dans une transaction lit les dernières données soumises par d'autres transactions dans la base de données (équivalent à la lecture actuelle)

lecture répétable

Quel que soit le nombre de fois qu'une opération de lecture est effectuée dans une opération de transaction, le résultat de la lecture sera le même.

Lecture fantôme

Lecture sale, lecture non répétable, lecture répétable, lecture fantôme, le plus difficile à comprendre est la lecture fantôme

Prenons mysql comme exemple :

Les lectures fantômes se produiront uniquement en mode de lecture répétable et ne se produiront pas dans d’autres niveaux d’isolement.

Exemples de phénomènes de lecture fantôme :

En mode lecture répétable, par exemple, s'il existe une table utilisateur avec un numéro de téléphone mobile comme clé primaire, deux éléments effectuent les opérations suivantes :

Le fonctionnement de la transaction A est le suivant :
1. Ouvrir la transaction
2. Interroger l'enregistrement avec le numéro X, qui n'existe pas
3. Insérer la donnée avec le
numéro On constate qu'il n'existe toujours pas (car c'est un lecture répétable, l'enregistrement lu X n'existe toujours pas)

Opération de transaction B : un enregistrement de

L'opération ci-dessus est comme une hallucination pour A. Il est clair que la requête X (les deuxième et quatrième étapes de A) n'existe pas, mais elle ne peut pas être insérée avec succès.

La lecture fantôme peut être comprise de cette façon : l'opération ultérieure dans la transaction (insérer le numéro X) nécessite le support de l'opération de lecture ci-dessus (interroger l'enregistrement du numéro Comme une hallucination.

Si vous ne parvenez toujours pas à le comprendre, continuez à lire ci-dessous pour une démonstration détaillée plus tard.

niveau d'isolement des transactions

Lorsque plusieurs transactions sont en cours en même temps, comment garantir l'exactitude des données dans la transaction en cours ? Par exemple, lorsque deux choses A et B sont en cours en même temps, A peut-il voir les données soumises par B ou Les données non soumises par B ? Cela dépend du niveau d'isolement de la transaction pour garantir que les effets produits par les différents niveaux d'isolement sont différents.

Le niveau d'isolation des transactions résout principalement les problèmes ci-dessus de visibilité et d'exactitude des données entre plusieurs transactions.

Il existe 4 types de niveaux d'isolement :

  1. Lecture non validée : READ-UNCOMMITTED

  2. Lecture soumise : LECTURE-COMMITTED

  3. Lecture répétable : RÉPÉTABLE-LECTURE

  4. SÉRIE : SÉRIALISABLE

Le niveau d'isolement dans les 4 ci-dessus devient de plus en plus fort, ce qui entraînera une concurrence de plus en plus faible de la base de données.

Vérifier le niveau d'isolement

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)

Paramètres du niveau d'isolement

En 2 étapes, modifiez le fichier et redémarrez mysql, comme suit :

Modifiez le fichier my.init dans MySQL et définissez le niveau d'isolement sur : READ-UNCOMMITTED, comme suit :

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=READ-UNCOMMITTED

Ouvrez la fenêtre cmd en tant qu'administrateur et redémarrez MySQL, comme suit :

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

Problèmes qui surviennent à différents niveaux d’isolement

niveau d'isolement sale lecture lecture non répétable Lecture fantôme
LECTURE-NON ENGAGÉ avoir avoir aucun
LECTURE-ENGAGÉE aucun avoir aucun
LECTURE RÉPÉTABLE aucun aucun avoir
SÉRIALISABLE aucun aucun aucun

Il existe quelques différences entre le tableau et Internet, principalement dans le domaine de la lecture fantôme. La lecture fantôme n'apparaîtra que dans le niveau de lecture répétable et n'existe pas dans les autres niveaux.

Montrons les problèmes de visibilité dans différents niveaux d'isolement en ouvrant deux fenêtres, appelées fenêtres A et B, et en nous connectant à MySQL dans les deux fenêtres.

READ-UNCOMMITTED : lecture non validée

Réglez le niveau d'isolement surREAD-UNCOMMITTED :

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=READ-UNCOMMITTED

redémarrez MySQL :

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

Vérifiez le niveau d'isolement :

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-UNCOMMITTED |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)

Effacez d’abord les données de la table test1 :

delete from test1;
select * from test1;

Effectuez les opérations suivantes dans 2 fenêtres par ordre chronologique :

temps Fenêtre A Fenêtre B
T1 démarrer la transaction ;
T2 sélectionnez * dans test1 ;
T3 démarrer la transaction ;
T4 insérer dans test1 les valeurs (1);
T5 sélectionnez * dans test1 ;
T6 sélectionnez * dans test1 ;
T7 commettre;
Q8 commettre;

Une fenêtre est la suivante :

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

La fenêtre B est la suivante :

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (1);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

regarde:

T2-A : Aucune donnée, T6-A : Il y a des données. B n'a pas soumis au moment T6. À ce moment-là, A a vu les données insérées par B, indiquant qu'une lecture sale a eu lieu .

T2-A : Aucune donnée, T6-A : Il y a des données. Les résultats de la requête sont différents, indiquant qu'une lecture répétable n'est pas possible .

Conclusion : Lorsque la lecture n'est pas validée, vous pouvez lire les données non validées d'autres transactions. Les résultats de plusieurs lectures sont différents et des lectures sales et des lectures non répétables se produisent.

READ-COMMITTED : lecture validée

Réglez le niveau d'isolement surREAD-COMMITTED

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=READ-COMMITTED

redémarrez MySQL :

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

Vérifiez le niveau d'isolement :

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | READ-COMMITTED |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)

Effacez d’abord les données de la table test1 :

delete from test1;
select * from test1;

Effectuez les opérations suivantes dans 2 fenêtres par ordre chronologique :

temps Fenêtre A Fenêtre B
T1 démarrer la transaction ;
T2 sélectionnez * dans test1 ;
T3 démarrer la transaction ;
T4 insérer dans test1 les valeurs (1);
T5 sélectionnez * dans test1 ;
T6 sélectionnez * dans test1 ;
T7 commettre;
Q8 sélectionnez * dans test1 ;
T9 commettre;

Une fenêtre est la suivante :

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

La fenêtre B est la suivante :

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (1);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

regarde:

T5-B : Il y a des données, Fenêtre T6-A : Aucune donnée, A ne peut pas voir les données de B, ce qui indique qu'il n'y a pas de lecture sale .

Fenêtre T6-A : aucune donnée, T8-A : a vu les données insérées par B, et B les a soumises à ce moment-là. A a vu les données soumises par B, ce qui signifie que les données soumises peuvent être lues .

T2-A, T6-A : Aucune donnée, T8-A : Il y a des données. Les résultats de plusieurs lectures sont différents, ce qui indique qu'une lecture répétable n'est pas possible .

Conclusion : Dans le cas d'une lecture validée, les données qui n'ont pas été soumises par d'autres transactions ne peuvent pas être lues, mais les données qui ont été soumises par d'autres transactions peuvent être lues. Les résultats de plusieurs lectures sont différents. Les lectures sales ne se produisent pas. , mais Lecture Commise, Ne peut pas être lu à plusieurs reprises.

REPEATABLE-READ : lecture répétable

Réglez le niveau d'isolement surREPEATABLE-READ

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=REPEATABLE-READ

redémarrez MySQL :

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

Vérifiez le niveau d'isolement :

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)

Effacez d’abord les données de la table test1 :

delete from test1;
select * from test1;

Effectuez les opérations suivantes dans 2 fenêtres par ordre chronologique :

temps Fenêtre A Fenêtre B
T1 démarrer la transaction ;
T2 sélectionnez * dans test1 ;
T3 démarrer la transaction ;
T4 insérer dans test1 les valeurs (1);
T5 sélectionnez * dans test1 ;
T6 sélectionnez * dans test1 ;
T7 commettre;
Q8 sélectionnez * dans test1 ;
T9 commettre;
T10 sélectionnez * dans test1 ;

Une fenêtre est la suivante :

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> select * from test1;
Empty set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    1 |
+------+
2 rows in set (0.00 sec)

La fenêtre B est la suivante :

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into test1 values (1);
Query OK, 1 row affected (0.00 sec)

mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    1 |
+------+
2 rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

regarde:

Fenêtres T2-A et T6-A : pas de données, T5-B : données. A ne peut pas voir les données de B, ce qui indique qu'il n'y a pas de lecture sale .

T8-A : Aucune donnée. B l'a soumis pour le moment. A ne peut pas voir les données soumises par B. Les résultats de trois lectures dans A sont les mêmes, indiquant qu'il n'y a aucune donnée, indiquant que la lecture peut être répétée .

Conclusion : dans le cas d'une lecture répétable, aucune lecture sale ne se produit, aucune donnée soumise par d'autres transactions n'est lue et les résultats de plusieurs lectures sont cohérents, la lecture peut donc être répétée.

Démonstration de lecture fantôme

Les lectures fantômes ne se REPEATABLE-READproduiront qu'au niveau (lecture répétable) et vous devez d'abord modifier le niveau d'isolement en lecture répétable.

Réglez le niveau d'isolement surREPEATABLE-READ

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=REPEATABLE-READ

redémarrez MySQL :

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

Vérifiez le niveau d'isolement :

mysql> show variables like 'transaction_isolation';
+-----------------------+----------------+
| Variable_name         | Value          |
+-----------------------+----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+----------------+
1 row in set, 1 warning (0.00 sec)

Préparez les données :

mysql> create table t_user(id int primary key,name varchar(16) unique key);
Query OK, 0 rows affected (0.01 sec)

mysql> insert into t_user values (1,'路人甲Java'),(2,'路人甲Java');
ERROR 1062 (23000): Duplicate entry '路人甲Java' for key 'name'

mysql> select * from t_user;
Empty set (0.00 sec)

Ci-dessus, nous avons créé la table t_user et ajouté une contrainte unique à name, ce qui signifie que name ne peut pas être répété, sinon une erreur sera signalée.

Effectuez les opérations suivantes dans 2 fenêtres par ordre chronologique :

temps Fenêtre A Fenêtre B
T1 démarrer la transaction ;
T2 démarrer la transaction ;
T3 -- Insérer 路人甲Java
dans les valeurs t_user (1,'passer A Java');
T4 sélectionnez * dans t_user ;
T5 -- 查看路人甲Java是否存在
select * from t_user where name='路人甲Java';
T6 commit;
T7 -- 插入路人甲Java
insert into t_user values (2,'路人甲Java');
T8 -- 查看路人甲Java是否存在
select * from t_user where name='路人甲Java';
T9 commit;

A窗口如下:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t_user where name='路人甲Java';
Empty set (0.00 sec)

mysql> insert into t_user values (2,'路人甲Java');
ERROR 1062 (23000): Duplicate entry '路人甲Java' for key 'name'
mysql> select * from t_user where name='路人甲Java';
Empty set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

B窗口如下:

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t_user values (1,'路人甲Java');
Query OK, 1 row affected (0.00 sec)

mysql> select * from t_user;
+----+---------------+
| id | name          |
+----+---------------+
|  1 | 路人甲Java    |
+----+---------------+
1 row in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

看一下:

A想插入数据路人甲Java,插入之前先查询了一下(T5时刻)该用户是否存在,发现不存在,然后在T7时刻执行插入,报错了,报数据已经存在了,因为T6时刻B已经插入了路人甲Java

然后A有点郁闷,刚才查的时候不存在的,然后A不相信自己的眼睛,又去查一次(T8时刻),发现路人甲Java还是不存在的。

此时A心里想:数据明明不存在啊,为什么无法插入呢?这不是懵逼了么,A觉得如同发生了幻觉一样。

SERIALIZABLE:串行

SERIALIZABLE会让并发的事务串行执行。

看效果:

将隔离级别置为SERIALIZABLE

# 隔离级别设置,READ-UNCOMMITTED读未提交,READ-COMMITTED读已提交,REPEATABLE-READ可重复读,SERIALIZABLE串行
transaction-isolation=SERIALIZABLE

重启mysql:

C:\Windows\system32>net stop mysql
mysql 服务正在停止..
mysql 服务已成功停止。

C:\Windows\system32>net start mysql
mysql 服务正在启动 .
mysql 服务已经启动成功。

查看隔离级别:

mysql> show variables like 'transaction_isolation';
+-----------------------+--------------+
| Variable_name         | Value        |
+-----------------------+--------------+
| transaction_isolation | SERIALIZABLE |
+-----------------------+--------------+
1 row in set, 1 warning (0.00 sec)

先清空test1表数据:

delete from test1;
select * from test1;

按时间顺序在2个窗口中执行下面操作:

时间 窗口A 窗口B
T1 start transaction;
T2 select * from test1;
T3 start transaction;
T4 insert into test1 values (1);
T5 select * from test1;
T6 commit;
T7 commit;

按时间顺序运行上面的命令,会发现T4-B这样会被阻塞,直到T6-A执行完毕。

可以看出来,事务只能串行执行了。串行情况下不存在脏读、不可重复读、幻读的问题了。

关于隔离级别的选择

  1. 需要对各种隔离级别产生的现象非常了解,然后选择的时候才能游刃有余

  2. 隔离级别越高,并发性也低,比如最高级别SERIALIZABLE会让事物串行执行,并发操作变成串行了,会导致系统性能直接降低。

  3. 具体选择哪种需要结合具体的业务来选择。

  4. 读已提交(READ-COMMITTED)通常用的比较多。

总结

  1. 理解事务的4个特性:原子性、一致性、隔离性、持久性

  2. 掌握事务操作常见命令的介绍

  3. set autocommit可以设置是否开启自动提交事务

  4. start transaction:开启事务

  5. start transaction read only:开启只读事物

  6. commit:提交事务

  7. rollback:回滚事务

  8. savepoint:设置保存点

  9. rollback to 保存点:可以回滚到某个保存点

  10. 掌握4种隔离级别及了解其特点

  11. 了解脏读、不可重复读、幻读

Je suppose que tu aimes

Origine blog.csdn.net/weixin_46228112/article/details/132696530
conseillé
Classement