幻读是指在同一个事务中,前后两次查询相同的范围时,得到的结果不一致,注意是范围查询。间隙锁就是解决幻读的问题。
MySQL的默认隔离级别是可重复读。按照红色标注的序号,并没有出现幻读问题,这是因为MySQL通过快照读,解决了可重复读这种隔离级别情况下的幻读问题!快照读,简单点来说就是数据有很多个版本,事务在并发执行的时候,某个事务读取到的是其中一个快照。
当前读:查询到的永远是数据库中最新的数据。适用如下这些语句:
select ... from table_name in share mode;
select ... from table_name for update;
insert;update;delete;
间隙锁是为了解决InnoDB存储引擎中可重复读导致的幻读问题,那么到底什么是间隙锁呢?我们先看如下的操作:
针对图中的第二条查询SQL语句:
select * from tb_lock where id > 1 and id < 5 for update;
该SQL很明显是当前读,而当前读读取的是数据库中最新的数据。那么现在有个问题:
此时如果另外有一个事务插入一条id为8的数据,再执行相同的SQL语句,是否就不会出现幻读了吗?
如果问题1的结果是没有出现幻读,肯定是通过锁机制,那么这又是如何上锁的?那么如果插入的id分别为8、12、17的数据,又会出现什么现象呢?id为12、17并不会让查询结果产生幻读吗?
针对问题一,如下图所示:
我们知道,当前读取的是数据库中最新的数据。右侧的数据如果能提交的话,左侧的查询必然会产生幻读问题,所以会通过上锁的方式阻止事务的提交,而这个锁就是间隙锁。
当你理解了问题二,我深信你一定会明白什么是间隙锁。
出现上面两图结果的原因在于,因为 tb_lock表中的数据id为1、4、7、9、15、19
mysql> select * from tb_lock;
+----+-----------+
| id | person_id |
+----+-----------+
| 1 | 1 |
| 4 | 9 |
| 7 | 20 |
| 9 | 22 |
| 15 | 27 |
| 19 | 33 |
+----+-----------+
6 rows in set (0.00 sec)
当查询id在(5,10)之间的时候
select * from tb_lock where id <10 and id>5 for update;
锁的并不是整个数据库表,而是查找离下限(5)最大的id值和上限(10)最小的id值,分别为4和15;然后锁的区间范围为(4,15],也就是说处于这个区间的id是无法插入进去的,所以导致了上面两张图的结果。
非范围: