面试题答案
一键面试读未提交(Read Uncommitted)
- MVCC工作原理:在该隔离级别下,事务可以读取到其他事务未提交的数据。MVCC机制中,每个数据行版本都有创建事务ID(xmin)和删除事务ID(xmax)。读未提交时,只要数据行版本存在且没有被标记为已删除(即xmax为空或者xmax对应的事务尚未提交),就可以被读取。
- 数据版本可见性规则:
- 事务可以看到所有已存在的数据行版本,即使创建这些版本的事务尚未提交。
- 数据行版本若有xmax,且xmax对应的事务已回滚,该版本对所有事务可见。
- 并发问题:脏读,即一个事务可以读取到另一个事务未提交的数据,如果未提交事务回滚,那么读取到的数据就是无效的。
- MVCC应对策略:由于读未提交隔离级别本身就允许脏读,MVCC在这种情况下没有额外的特殊策略来防止脏读,只是按照上述可见性规则让事务读取数据。
读已提交(Read Committed)
- MVCC工作原理:事务只能读取到已提交的事务的数据。MVCC通过检查数据行版本的xmin和xmax来确定数据是否可见。
- 数据版本可见性规则:
- 数据行版本的xmin对应的事务已提交,且xmax为空或者xmax对应的事务已回滚,该版本对当前事务可见。
- 如果xmin对应的事务正在进行(未提交),则该版本不可见。
- 并发问题:不可重复读,即同一个事务中多次读取同一数据,由于其他事务在期间提交了对该数据的修改,导致每次读取结果不一致。
- MVCC应对策略:每次读取数据时,MVCC根据上述可见性规则获取最新已提交的数据版本。为了避免不可重复读,应用层可以通过对数据加锁等方式来确保一致性,但MVCC本身在此隔离级别下不提供直接防止不可重复读的机制。
可重复读(Repeatable Read)
- MVCC工作原理:在可重复读隔离级别下,事务在开始时会建立一个快照,在事务执行期间,所有的读操作都基于这个快照。MVCC机制通过快照来管理数据版本。
- 数据版本可见性规则:
- 数据行版本的xmin对应的事务在快照创建之前已提交,且xmax为空或者xmax对应的事务在快照创建之前已回滚,该版本对当前事务可见。
- 如果xmin对应的事务在快照创建之后开始(未提交),则该版本不可见。
- 并发问题:幻读,即事务在执行过程中,由于其他事务插入了符合查询条件的新数据,导致多次执行相同查询时返回的结果集不一致。
- MVCC应对策略:通过快照机制,MVCC确保事务在整个执行过程中看到的数据是一致的。为了防止幻读,PostgreSQL在可重复读隔离级别下会使用谓词锁(Predicate Locks),对于符合查询条件的范围加锁,防止其他事务插入新数据。
串行化(Serializable)
- MVCC工作原理:串行化隔离级别是最高的隔离级别,它通过对事务进行排序,模拟事务串行执行的效果。MVCC仍然用于管理数据版本,但结合了更严格的并发控制机制。
- 数据版本可见性规则:类似于可重复读,事务基于一个快照进行操作,可见性规则与可重复读类似,但增加了额外的检测机制。
- 并发问题:理论上无并发问题,因为事务被串行化执行。但在实际实现中,如果并发事务之间的冲突检测失败,会导致事务回滚。
- MVCC应对策略:PostgreSQL使用SI(Snapshot Isolation)和SSI(Serializable Snapshot Isolation)机制。在SI基础上,SSI通过检测事务间的读写依赖关系来避免并发事务执行顺序导致的错误。如果检测到可能导致非串行化执行的依赖关系,相关事务会被回滚,以确保最终的串行化执行效果。