可重复读隔离级别是如何避免幻读的
15 分钟阅读
•
1283 字
+
1548 词
MySQL InnoDB 引擎的默认隔离级别虽然是==「可重复读」,但是它很大程度上避免幻读现象(并不是完全解决了)==,解决的方案有两种:
- 针对== 快照读 ==( 普通 select 语句 ),是== 通过 MVCC 方式解决了幻读 ==,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,即使中途有其他事务插入了一条数据,是查询不出来这条数据的,所以就很好了避免幻读问题。
- 针对== 当前读 ==( select ... for update 等语句(加锁的语句)),是== 通过 next-key lock(记录锁+间隙锁)方式解决了幻读 ==,因为当执行 select ... for update 语句的时候,会加上 next-key lock,如果有其他事务在 next-key lock 锁范围内插入了一条记录,那么这个插入语句就会被阻塞,无法成功插入,所以就很好了避免幻读问题。
快照读是如何避免幻读的?
当前读是如何避免幻读的?
select ... for update
这种查询语句是当前读,每次执行的时候都是读取最新的数据。
接下来,我们假设
select ... for update
当前读是不会加锁的(实际上是会加锁的),在做一遍实验。
幻读被完全解决了吗?
第一个发生幻读现象的场景
sql
# 事务 A
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from t_stu where id = 5;
Empty set (0.01 sec)
sql
# 事务 B
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into t_stu values(5, '小美', 18);
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql
# 事务 A
mysql> update t_stu set name = '小林coding' where id = 5;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from t_stu where id = 5;
+----+--------------+------+
| id | name | age |
+----+--------------+------+
| 5 | 小林coding | 18 |
+----+--------------+------+
1 row in set (0.00 sec)
第二个发生幻读现象的场景
- T1 时刻:事务 A 先执行「 快照读语句 」:select * from t_test where id > 100 得到了 3 条记录。
- T2 时刻:事务 B 往插入一个 id= 200 的记录并提交;
- T3 时刻:事务 A 再执行「 当前读语句 」 select * from t_test where id > 100 for update 就会得到 4 条记录,此时也发生了幻读现象。