mysqlの4つの独立性レベルの詳細

4299 ワード

本稿では、mysqlの4つの独立性レベルを完全に理解するために、一連の詳細なsql文を使用します.次の例では、2つのセッション(session)が使用され、各セッションで1つのトランザクションが開き、それぞれsession A、トランザクションAとして記録される.セッションB、トランザクションB.
準備作業
まずテーブル「student」を新規作成し、2行のデータを挿入します.
CREATE TABLE `student` (
  `id` int(11) NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

insert student(id, name) values(1, 'zhangsan'), (2, 'lisi');

表のデータは次の図のとおりです.
id
name
1
zhangsan
2
lisi
次に、次のsqlを使用してデータベースのデフォルトの独立性レベルをクエリーします.
select @@transaction_isolation; 

デフォルトの独立性レベルが「繰り返し読み取り可能」であることがわかります.
REPEATABLE-READ

次に、各独立性レベルの意味をsqlにより詳細に説明する.
read-uncommitted
「読み取り未送信」を確認し、まずセッション(sessionA)を開き、データベースの独立性レベルを「read-uncommitted」に設定します.
set session transaction_isolation = 'read-uncommitted';

トランザクションAを開く
start transaction;

nameを更新しstudentテーブルをクエリーする
update student set name = 'hehe';
select * from student;

結果は次のとおりです.
id
name
1
hehe
2
hehe
現在のトランザクションAでは、上記のupdate文の変更はコミットされていません(start transactionの後、コミットするには手動でcommitを実行する必要があります)ここで、別のセッション(session B)を開き、独立性レベルを「読み取り未コミット」に設定します.
set session transaction_isolation = 'read-uncommitted';

次に、トランザクションBを開き、テーブル'student'をクエリーします.
start transaction;
select * from student;

結果は次のとおりです.
id
name
1
hehe
2
hehe
このとき、トランザクションAとBはコミットされていません.トランザクションBでトランザクションAにコミットされていないデータが検出されました.これはダーティリードです.
read-committed
次に、コミットされていないトランザクションAとトランザクションBが最初にコミットされたことを確認します(commit;).セッションAとセッションBの独立性レベルを「読み取りコミット」に設定します.
set session transaction_isolation = 'read-committed';

セッションBでトランザクションBを開き、テーブル'student'を問合せます.
start transaction;
select * from student;

結果は次のとおりです.
id
name
1
hehe
2
hehe
セッションAでトランザクションAを開き、studentを更新
start transaction;
update student set name = 'zhangsan' where id = 1;

トランザクションAがコミットされていない場合は、再度トランザクションBでstudentを問い合わせる
select * from student;

結果は上記と同じです.
id
name
1
hehe
2
hehe
「読み取りコミット」で汚れた読み取りが回避されたことを示します.トランザクションAでのコミットの実行
commit;

トランザクションBでクエリーstudentを再実行
select * from student;

結果は次のとおりです.
id
name
1
zhangsan
2
hehe
この時点で、トランザクションAはコミットされ、トランザクションBはコミットされません.一方、トランザクションBは、トランザクションAがコミットしたデータを読み取ることができ、前回のクエリの結果とは異なり、重複して読むことはできません.読み取りコミットは、汚れた読み取りの問題を回避します.
repeatable-read
次に、リピート可能な読み取りを確認します.まず、上記のトランザクションAとトランザクションBをコミットし、セッションAとセッションBの独立性レベルを「繰り返し読み取り可能」に設定します.
set session transaction_isolation = 'repeatable-read';

セッションBで、トランザクションBを開いてstudentを問合せます
start transaction;
select * from student;

結果は次のとおりです.
id
name
1
zhangsan
2
hehe
セッションAでトランザクションAを開き、データを挿入します.
start transaction;
insert student (id, name)values(3, 'haha');

このときトランザクションAはコミットされず、トランザクションBに同じidが3の1行のデータが挿入される
insert student (id, name)values(3, 'haha');

エラーは次のとおりです.
[Err] 1062 - Duplicate entry '3' for key 'PRIMARY'

再クエリーstudent
select * from student;

やはり
id
name
1
zhangsan
2
hehe
トランザクションBでstudentをクエリーすると、2行のデータ(idは1と2)しかありませんが、idが3のデータを挿入すると、idが3のデータが存在していると誤報し、これが幻読みであることがわかります.「繰り返し可能」では、繰り返し不可能な問題を回避できます.
serializable
これは検証されず、分かりやすく、「シリアル化」は幻読の問題を避けることができます.
まとめ
独立性レベル
汚読
繰り返し不可
まぼろし読み
read-uncommitted
1
1
1
read-committed
0
1
1
repeatable-read
0
0
1
serializable
0
0
0
特に、繰り返し不可と幻読みの違いはあまり明らかではありません.繰り返し不可とは、あるトランザクションが別のトランザクションからコミットされた変更を読み、幻読みとは、あるトランザクションが別のトランザクションの削除データを感じていることを意味します.つまり前者は「添削改査」の「改」を指し、後者は「添削」を指す.