Open12
MySQL 8: 分離レベル
ピン留めされたアイテム
問題
- ダーティリード
- ファジーリード
- ノンリピータブルリード
- ファントムリード
これらとどう付き合うか
READ UNCOMMITTED
コミットされていない別セッションの更新が見える
Reader> select * from item;
+----+------+-------+
| id | name | price |
+----+------+-------+
| 1 | foo | 1000 |
| 2 | bar | 2000 |
+----+------+-------+
2 rows in set (0.01 sec)
Reader> set session transaction isolation level read uncommitted;
Query OK, 0 rows affected (0.00 sec)
Reader> select * from item;
+----+------+-------+
| id | name | price |
+----+------+-------+
| 1 | foo | 1000 |
| 2 | bar | 5000 |
+----+------+-------+
2 rows in set (0.00 sec)
ダーティーリードが起きる
READ COMMITTED
コミットされたものなら見える
Reader> select * from item;
+----+------+-------+
| id | name | price |
+----+------+-------+
| 1 | foo | 1000 |
| 2 | bar | 2000 |
+----+------+-------+
2 rows in set (0.00 sec)
commit
Reader> select * from item;
+----+------+-------+
| id | name | price |
+----+------+-------+
| 1 | foo | 1000 |
| 2 | bar | 5000 |
+----+------+-------+
2 rows in set (0.00 sec)
ファジーリードが起きる
REPEATABLE READ
一度参照した結果が繰り返される
( 一度参照というか、トランザクション開始前のものが繰り返し参照できるっぽい )
Reader> select * from item;
+----+------+-------+
| id | name | price |
+----+------+-------+
| 1 | foo | 1000 |
| 2 | bar | 2000 |
+----+------+-------+
2 rows in set (0.00 sec)
update
Reader> select * from item;
+----+------+-------+
| id | name | price |
+----+------+-------+
| 1 | foo | 1000 |
| 2 | bar | 2000 |
+----+------+-------+
2 rows in set (0.00 sec)
commit
Reader> select * from item;
+----+------+-------+
| id | name | price |
+----+------+-------+
| 1 | foo | 1000 |
| 2 | bar | 5000 |
+----+------+-------+
2 rows in set (0.01 sec)
トランザクション開始時にスナップショットを取得する
読み取り時にロックはしない
SERIALIZABLE
参照もロックする
Reader> begin;
Query OK, 0 rows affected (0.01 sec)
Reader> select * from item;
+----+------+-------+
| id | name | price |
+----+------+-------+
| 1 | foo | 1000 |
| 2 | bar | 2000 |
+----+------+-------+
2 rows in set (0.01 sec)
Writer> update item set price = 5000 where id = 2;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
Dirty Read
コミットしてないものが見える
Reader> begin;
Reader> select * from kv;
+----+-------+
| id | value |
+----+-------+
| 0 | zero |
| 5 | five |
| 10 | ten |
+----+-------+
Writer> begin;
Writer> insert into kv (id, value) values (20, 'twenty');
Reader> select * from kv;
+----+--------+
| id | value |
+----+--------+
| 0 | zero |
| 5 | five |
| 10 | ten |
| 20 | twenty |
+----+--------+
Fuzzy Read
取得した値が変わる
Reader> begin;
Reader> select * from kv;
+----+-------+
| id | value |
+----+-------+
| 0 | zero |
| 5 | five |
| 10 | ten |
+----+-------+
Writer> begin;
Writer> update kv set value = 'V' where id = 5;
Reader> select * from kv;
+----+-------+
| id | value |
+----+-------+
| 0 | zero |
| 5 | V |
| 10 | ten |
+----+-------+
Phantom Read
取得した行が変わる
Reader> begin;
Reader> select * from kv;
+----+-------+
| id | value |
+----+-------+
| 0 | zero |
| 5 | five |
| 10 | ten |
+----+-------+
Writer> begin;
Writer> delete from kv where id = 5;
Reader> select * from kv;
+----+-------+
| id | value |
+----+-------+
| 0 | zero |
| 10 | ten |
+----+-------+
Repeatable Read における Fuzzy Read
予想通り発生しない
Reader> select * from kv where id = 5;
+----+-------+
| id | value |
+----+-------+
| 5 | five |
+----+-------+
Writer> begin;
Writer> update kv set value = 'V' where id = 5;
Reader> select * from kv where id = 5;
+----+-------+
| id | value |
+----+-------+
| 5 | five |
+----+-------+
Writer> commit;
Reader> select * from kv where id = 5;
+----+-------+
| id | value |
+----+-------+
| 5 | V | -- read committed は包含する
+----+-------+
Repeatable Read における Phantom Read
予想に反して発生しない
なんか InnoDB だと起きないってやつだっけ?
Reader> select * from kv order by id limit 1;
+----+-------+
| id | value |
+----+-------+
| 0 | zero |
+----+-------+
Writer> begin;
Writer> insert into kv (id, value) values (-1, 'minus one');
Reader> select * from kv order by id limit 1;
+----+-------+
| id | value |
+----+-------+
| 0 | zero |
+----+-------+