面试官:什么是快照读?什么是当前读?有什么区别?
大家好,我是君哥。
使用 MySQL 时,我们经常会听到快照读、当前读这样的概念,今天我们就来聊一聊快照读、当前读。
快照读和当前读,主要区别在于是否读取到最新提交的数据,是否需要加锁,它们对数据库的并发性能有所不同。
1.快照读
快照读,读取的是数据的快照,通过读视图,提供非阻塞读取,代替加锁机制,提高并发性能。
我们知道,MySQL 事务隔离级别有 4 个:
- 串行化(Serializable):事务对数据读写都是串行化的。
- 可重复读(Repeatable Read):事务执行过程中,多次读取同一行数据,读取结果一致。MySQL 默认隔离级别就是可重复读。
- 读已提交数据(Read Committed):事务执行过程中,如果有其他事务修改了数据并且提交事务,当前事务可以读取到最新提交的数据。
- 读未提交数据(Read Uncommitted):事务执行过程中,可以读取到其他事务未提交的数据。
其中可重复读和读已提交数据,依托 MVCC(多版本并发控制)实现了快照读。
不同的是,可重复读是在事务开始时创建视图,每个事务就使用一个快照,所以多次读取结果是一样的,看不到新提交的数据。而读已提交是在每次语句执行前创建新的视图,所以能读取到新提交的数据。
比如有一张表 t_acct,其中有 id,account、amount 三个字段,在一个事务中有一条 SQL 语句被执行了 3 次:
select amount from t_acct where id=10;
在可重复读隔离级别下,读取到的数据如下:
图片
在读已提交隔离级别下,读取到的数据如下图:
图片
总结,快照读的特点就是读取视图数据,不加锁,非阻塞,执行 SQL 语句一般是简单查询:
SELECT xxx FROM table WHERE 条件
2.当前读
跟快照读对应的就是当前读,特点是读取数据最新提交的版本,在读取时会对数据进行加锁,以防止其他事务并发修改这条数据。优点是强一致,可以读取到数据最新版本,防止丢失更新。缺点是有加锁带来的阻塞和性能损耗。
当前读涉及的 SQL 如下:
SELECT xxx FROMTABLELOCKINSHAREMODE (共享锁);
SELECT xxx FROMTABLEFORUPDATE (排它锁)
UPDATETABLEset xxx (更新前先加排它锁)
DELETEFROMTABLEWHERE xxx (删除前先加排它锁)
INSERTINTOTABLE xxx (加排它锁)
3.总结
当前读和快照读的区别总结如下:
差异点 | 快照读 | 当前读 |
数据版本 | 基于快照,不一定最新 | 最新提交版本 |
是否加锁 | 不加 | 加锁 |
一致性 | 可能有不一致情况 | 强一致 |
并发性 | 强 | 可能有阻塞 |
实现原理 | MVCC | 数据库锁 |
适用隔离级别 | 可重复读、读已提交 | 全部 |
对于简单的数据查询,不要求查询最新提交数据,可以考虑使用快照读。如果要求读取到最新提交数据,那就考虑使用当前读。