快照
快照是一个指定时间点的数据表示,也就是,在指定时间点的数据版本,即使其他事务对源数据版本做出修改,快照对应的数据版本也不会发生变化,主要是用于事务隔离级别中提供一致性读。
一致性读
一致性读是指一个读操作使用快照信息呈现基于时间点的查询结果,即使在查询的过程中同时存在其他事务对相同的数据记录执行更新的操作。如果已查询的数据记录已被其他事务修改,InnoDB依然可以从重做日志(undo log)中重新构建出原始的数据记录。该技术可以避免一些锁带来的问题,例如,强迫一个事务等待其他事务执行完成,从而降低并发性。
使用可重复读的事务隔离级别,快照是基于第一次读操作(时间点)而获取到的数据版本。使用读提交的事务隔离级别,快照是基于每次读操作(不断变化的时间点,时间点取决于其他事务提交的数据版本的时间点)而获取到的数据版本。
一致性读是InnoDB处理SELECT语句的默认模式,其使用读提交或者可重复读的事务隔离级别。一致性读没有对访问的数据表设置任何锁,一个会话在执行一致性读期间,其他会话可以自由地修改这些数据表。
一致性无锁读
如前面所述,一致性读是指InnoDB使用多数据版本的控制技术呈现一个基于时间点的数据库查询结果,该查询能看到发生在对应时间点之前的由事务提交的数据变化,该查询不能看到发生在对应时间点之后的由事务提交或者事务回滚的数据变化。例外的情况是,查询能看到同一个事务内更早的语句更新的变化,也就是,如果用户A的会话更新一个数据表中的一些行记录,一个SELECT查询语句能看到这些行记录的最新版本,也可能看到这些行记录的更早版本,如果同时其他用户的会话更新相同数据表的相同行记录,则例外的情况是,用户A的会话可能看到的是一个永远不在数据库中存在的数据表的状态(由于并发性,数据可能已经被覆盖了)。
如果一个事务的隔离级别是可重复读(默认级别),在同一个事务中的一致性读是读取由第一次读确立的快照,如果想读到更新的快照,可以先提交当前的事务,再发起新的查询操作。
如果一个事务的隔离级别是读提交,在同一个事务中的一致性读是每次读取由该次读确定立的快照(在并发中,如果存在其他事务提交新的数据版本,则每次读到数据版本不相同)。
假设,当前数据库使用可重复读的事务隔离级别,会话A执行SELECT语句查询的时候,数据库返回一个时间点A的快照,随后,其他事务B删除会话A中查询对应的记录并提交事务,则会话A不能看到已经被删除的记录,插入或者更新操作的处理方式与查询的处理方式相同。
快照技术是应用于数据库的查询操作,而不同事务之间对相同的行记录的更新、删除、增加操作会相互影响,如果事务A增加或者修改一些行记录并提交事务,而其他事务B的删除或者更新语句会影响之前事务A的提交(事务隔离级别是可重复读),即使事务B的会话查询不到事务A的会话中的提交。如果事务A更新或者删除其他事务B的提交,则事务A的会话能看到自身的提交,举例如下所示:
先提交会话中的事务,再执行查询,可以使用语句SELECT或者语句START TRANSACTION WITH CONSISTENT SNAPSHOT获取到更新之后的快照,这种机制是多版本并发控制(MVCC)。
假设,存在会话A与会话B,只有在会话A与会话B的事务都已经提交,然后,会话A再执行查询才能获取到新版本的快照,举例如下所示:
如果会话中需要时刻看到最新的快照,则使用读提交的事务隔离级别或者使用有锁读(后续章节中详细描述),举例如下所示:
使用读提交的事务隔离级别,每个事务读取自身获取到最新的快照,而使用FOR SHARE语句,则使用有锁读,SELECT语句阻塞直到包括最新快照的事务结束,再获取最新的快照。
一致性读并不是在全部的数据定义语言中使用,如下所示:
|
语句INSERT INTO ... SELECT或者语句UPDATE ... (SELECT)或者语句CREATE TABLE ... SELECT执行读值时的处理如下所示:
|