并发影响

修改数据的用户会影响同时读取或修改相同数据的其他用户。即这些用户可以并发访问数据。如果数据存储系统没有并发控制,则用户可能会看到以下负面影响:

  • 丢失更新

  • 未提交的依赖关系(脏读)

  • 不一致的分析(不可重复读)

  • 幻读

  • 由于行更新导致读取缺失和重复读

丢失更新

当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,会发生丢失更新问题。每个事务都不知道其他事务的存在。最后的更新将覆盖由其他事务所做的更新,这将导致数据丢失。

例如,两个编辑人员制作了同一文档的电子副本。每个编辑人员独立地更改其副本,然后保存更改后的副本,这样就覆盖了原始文档。最后保存其更改副本的编辑人员覆盖另一个编辑人员所做的更改。如果在一个编辑人员完成并提交事务之前,另一个编辑人员不能访问同一文件,则可避免此问题。

未提交的依赖关系(脏读)

当第二个事务选择其他事务正在更新的行时,会发生未提交的依赖关系问题。第二个事务正在读取的数据还没有提交并且可能由更新此行的事务所更改。

例如,一个编辑人员正在更改电子文档。在更改过程中,另一个编辑人员复制了该文档(该副本包含到目前为止所做的全部更改)并将其分发给预期的用户。此后,第一个编辑人员认为目前所做的更改是错误的,于是删除了所做的编辑并保存了文档。分发给用户的文档包含不再存在的编辑内容,并且这些编辑内容应视为从未存在过。如果在第一个编辑人员保存最终更改并提交事务之前,任何人都不能读取更改的文档,则可以避免此问题。

不一致的分析(不可重复读)

当第二个事务多次访问同一行而且每次读取不同的数据时,会发生不一致的分析问题。不一致的分析与未提交的依赖关系类似,因为其他事务也是正在更改第二个事务正在读取的数据。但是,在不一致的分析中,第二个事务读取的数据是由已进行了更改的事务提交的。此外,不一致的分析涉及多次(两次或更多)读取同一行,而且每次信息都被其他事务更改,因此我们称之为“不可重复读”。

例如,编辑人员两次读取同一文档,但在两次读取之间,作者重写了该文档。当编辑人员第二次读取文档时,文档已更改。原始读取不可重复。如果在编辑人员完成最后一次读取文档之前,作者不能更改文档,则可以避免此问题。

幻读

当对某行执行插入或删除操作,而该行属于某个事务正在读取的行的范围时,会发生幻读问题。由于其他事务的删除操作,事务第一次读取的行的范围显示有一行不再存在于第二次或后续读取内容中。同样,由于其他事务的插入操作,事务第二次或后续读取的内容显示有一行并不存在于原始读取内容中。

例如,一个编辑人员更改作者提交的文档,但当生产部门将其更改内容合并到该文档的主副本时,发现作者已将未编辑的新材料添加到该文档中。与不可重复读的情况相似,如果在编辑人员和生产部门完成对原始文档的处理之前,任何人都不能将新材料添加到文档中,则可以避免此问题。

由于行更新导致读取缺失和重复读

  • 缺失一个更新行或多次看到某更新行

    在 READ UNCOMMITTED 级别运行的事务不会发出共享锁来防止其他事务修改当前事务读取的数据。在 READ COMMITTED 级别运行的事务会发出共享锁,但是在读取行后会释放行锁或页锁。无论哪种情况,在您扫描索引时,如果另一个用户在您读取期间更改行的索引键列,则在键更改将行移至您的扫描位置之前的位置时,该行可能会再次出现。同样,在键更改将行移至您已读取的索引中的某位置时,该行将不会出现。若要避免这种情况,请使用 SERIALIZABLE 或 HOLDLOCK 提示,或者使用行版本控制。有关详细信息,请参阅表提示 (Transact-SQL)数据库引擎中基于行版本控制的隔离级别

  • 缺失非更新目标的一行或多行

    使用 READ UNCOMMITTED 时,如果您使用分配顺序扫描(使用 IAM 页)查询读取行,则当其他事务导致页拆分时,可能会缺失行。当使用已提交的读取时不会发生这种情况,因为在页拆分期间将会保持表锁;当表没有聚集索引时也不会发生这种情况,因为更新不会导致页拆分。