参考链接(博客)
参考链接(Github CS-Notes)
快照读(官网)
为什么一个事务能够读到其他事务修改但未提交的数据
事务日志
事务
首先,数据库的事务的原子性是指事务要么全部完成,要么全部没完成(回滚)。事务本身并不能保证其隔离性,还需要其它操作辅助实现。
- commit只是保证你数据库故障时候回滚不会回滚这个事务了,或者说只要commit这个语句写入redo log了就算缓冲区的数据没有写回硬盘或者其他持久化设备也是可以通过redo log将新的值写回去,整个事务没有丢失。
- 内存的读写速度比硬盘的读写速度快很多,数据库不可能每个操作都去访问硬盘。所以读取操作一般都是和内存打交道,因此如果我们没有进行一些事务的隔离操作,一个事务就可能会读到其它事务修改但未提交的数据。换句话说,并不是说事务commit之后,数据才修改了。
事务日志
redo log提供数据库恢复和写入磁盘的功能。undo log提供事务回滚的功能。
快照读
快照读的实现参考博客和github那两个链接。重点是自己的思考。
快照读如何实现读已提交
读已提交
事务可能出错回滚,如果快照读要实现读已提交,则在一个事务内,每一条select语句都应该生成一个新的ReadView。(官网: With READ COMMITTED isolation level, each consistent read within a transaction sets and reads its own fresh snapshot.)。其实如果不生成新的ReadView也满足读已提交,但是生成新的ReadView可以使得读取到的数据是较新的版本。
可重复读
事务t读一份数据,并发地,其它事务可能修改了数据,t再次读的数据和之前读的数据就会不一致了。因此,我们需要在开启事务后的第一个select语句生成一个快照,也可以使用 START TRANSACTION WITH CONSISTENT SNAPSHOT 提前在事务开启时就生成快照。(官网: You can advance your timepoint by committing your transaction and then doing another SELECT or START TRANSACTION WITH CONSISTENT SNAPSHOT.)
生成快照,同一个事务之后的select就都使用这个快照了,不会再生成快照,这样子才能保证可重复读。代价就是读取到的数据版本可能比较落后。