![5371a1d5befc7c911ca0269dd4a0214b.png](https://i-blog.csdnimg.cn/blog_migrate/5e3806741c6980f7ae9490a96bd2980a.jpeg)
以前,对可重复读的理解,就是别的事务的提交,对当前事务的查询结果,不会产生影响;
后来,知道事务在一开始的时候,会生成一个快照;
不过这样的对可重复读的理解,依然肤浅。
在我看来,要想真正弄懂可重复读,至少要把以下几个名词,能够串起来,解释清楚:
- 快照读(consistent nonlocking reads)
- 当前读(locking reads)
- MVCC
- gap lock
- next-key lock
- 幻读
从这一讲开始,我就试着用各种例子,把这些知识串起来,给大家讲清楚到底什么是Repeatable Read.
先从简单的开始,我们说的“快照”,是什么时候开始创建的?
有同学说,快照在begin的时候就创建了。
是吗?
我们建一张极简的表:
CREATE
插入两条数据:
insert
然后按照下面表格的顺序,在两个会话窗口执行如下sql语句:
![12b001b0d0156b67cc05890166825ac7.png](https://i-blog.csdnimg.cn/blog_migrate/a61b338df8cf4534aec84e76f240b3be.jpeg)
你可以像我这样,打开两个命令行窗口,分别执行:
![c65e1d44321dcb0f67ff06b60d51b88c.png](https://i-blog.csdnimg.cn/blog_migrate/30ca525b7fce1e026caa10c919ba79b0.jpeg)
如果Mysql真的是在begin的时候,就创建了快照,那么session A执行select语句时,查询到的c应该是1,但是,实际查询到的,却是3,说明begin后,快照并没有立刻生成。
于是我们试着把select语句放到session B的update语句之前:
![29865ead78ef0886dcf73ddaa35565e8.png](https://i-blog.csdnimg.cn/blog_migrate/2ecb15d9d50c720697b09c2efc958cb3.jpeg)
这次你会发现,session A在执行第二天select语句时,查询到的c还是1,说明快照已经在执行第一条select语句时生成了,session B的update对session A不产生影响。
那么是不是就可以说,快照会在执行那些操作mysql数据库的sql语句时生成呢?
并不是,只有“快照读”的sql语句,才会生成快照,比如不加锁的select语句;
而“当前读”的sql语句,是不会生成快照的,比如update,select … for update, select .. lock in share mode等;
所以下面这个例子,session A在select时看到的还会是被session B修改的数据,因为在update时并没有生成快照:
![bcac2587a55561fe912f08ed279c0a27.png](https://i-blog.csdnimg.cn/blog_migrate/ddc3e2771e63174e9ab3d8444e1c28d3.jpeg)
那你说,我就是想在begin时就生成快照呢?
送你一条sql:
start
小结一下:
- 可重复读的关键,来自于“快照”
- “快照”并不是在begin后就生成,而是在第一条“快照读”语句后才生成
那么问题又来了,“快照”到底是啥?是对当前数据的全量拷贝吗?难道每开启一个事务,都要把当前数据库的数据拷贝一份出来?
下一讲,咱们来聊聊可重复读的实现原理 —— MVCC。
参考
- 《Mysql实战45讲》丁奇
- Innodb Transaction Isolation Levels