比如事务 A 查询主键 id = 1 的行数据列 age = 10,不管事务 B 是否对该 age 值做出改变,事务 A 的多条查询 SQL 语句,查询 age 的值一定一直都是 age = 10;
在可重复读级别下,快照读是基于 MVCC 和 undo log 实现的,多个 readView 组成一个回滚日志 undo log。在该级别下,MVCC 完全解决了重复读,也在一定程度上避免了幻读,但是这种避免幻读的方式,是利用快照读的特性,在某事务开始时的第一个 select 生成一个 readView,该 readView 某种意义上算是第一个 select 时的历史数据。对事务 A 使用快照读的方式,表面上看避免了幻读,但如果其他事务 B 修改了数据,事务 A 再修改数据,然后事务 A 再查询数据,这时候事务 A 就会出现由事务 B 修改的数据,即事务 B 修改的数据并没有实时显示。
要完全避免这种现象,需要使用当前读的方式。
1.4.3 当前读
当前读可以读取最新的数据,完全避免了可重复读和幻读现象,它保证数据的一致性,同一个事务内部读取某一条数据时,数据都是一样的。
在可重复读级别下,当前读是通过行锁 (record lock) 与间隙锁 (gap lock) 实现的。以两个正在进行的事务 A, B 进行举例,其中事务 A 两条 SQL 语句,且第二条是 insert 语句,事务 B 是一个 insert 语句:
事务 A 开始时生成一个 readView (id = n),执行第一个 SQL 语句时,读取的是当前的 readView 值 (id = n);
事务 B 开始,首先生成 id = n+1 的 readView;
事务 B 使用索引进行插入(或 update 等操作)时,InnoDB 会在事务 B 中将当前行与上一个行加锁,对当前行用行锁 (record lock) 加锁,对上一行用间歇锁 (gap lock) 加锁(锁住一部分区域数据);
事务 A 执行第二个 SQL 即 insert 语句,这时候由于事务 B 还没有提交,所以没有释放数据锁,此时阻塞等待;
事务 B 执行完毕,释放锁,事务 A 的第二个 SQL 获取锁,读到当前最新的数据 (readView id = n+1);
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。