描述并发

已完成

多用户数据库的核心功能是并发。 并发通过使用锁定和阻塞来使数据在许多用户同时更新和读取时保持一致。 例如,由于发货成本,我们所有的产品都有 5 美元的价格上涨。 同时,由于汇率的原因,所有产品的价格都下降了 3%。 如果这些更新恰好同时发生,最终价格将是可变的,并且可能存在许多错误。 使用锁定,可以确保一个更新将在另一个更新开始之前完成。

并发是在事务级别上发生的。 写入事务可能会阻止其他事务更新,甚至读取相同的数据。 同样,读取事务可以阻止其他读者,甚至是某些写入程序。 因此,必须避免不必要冗长的事务或涉及过多数据的事务。

有许多特定的事务隔离级别可用于定义数据库系统如何处理多个用户。 在本模块中,我们将介绍隔离级别、乐观锁定和悲观锁定的广泛类别。

注释

除并发之外,事务锁定的完整细节更多与性能相关,而不仅仅是取决于代码,尽管优质代码表现更佳。 有关更多详细信息,请查看深入 的 SQL Server 事务锁定和行版本控制指南 。 有关阻止的信息,另请查看 SQL Server 性能文档

乐观并发

使用乐观锁定时的假设是很少发生冲突的更新。 在事务开始时,记录数据的初始状态。 在提交事务之前,当前状态将与初始状态进行比较。 如果状态相同,则事务已完成。 如果状态不同,则回滚事务。

例如,你有一个包含去年销售订单的表。 此数据很少更新,但会经常运行报告。 通过使用乐观锁定,事务不会相互阻止,因此系统运行效率更高。 遗憾的是,在过去几年中发现了错误,需要进行数据和更新。 当一个事务更新每一行时,另一个事务同时对单个行进行轻微编辑。 由于数据的状态已在初始事务运行时发生变化,因此将回滚整个事务。

悲观并发

使用悲观锁定时的假设是数据同时发生许多更新。 通过使用锁,只能同时发生一个更新,并且更新发生时会阻止读取数据。 这可以防止出现如前面示例所示的大规模回滚,但可能导致不必要地阻止查询。

在决定是否使用乐观或悲观并发来确保最佳性能时,请务必考虑数据的性质和数据上运行的查询。

快照隔离

SQL Server 中有五个不同的隔离级别,但在本模块中,我们将只专注于READ_COMMITTED_SNAPSHOT_OFF和READ_COMMITTED_SNAPSHOT_ON。 READ_COMMITTED_SNAPSHOT_OFF 是 SQL Server 的默认隔离级别。 Azure SQL 数据库的默认隔离级别是 READ_COMMITTED_SNAPSHOT_ON。

如果查询使用的是读取已提交事务隔离级别,则 READ_COMMITTED_SNAPSHOT_OFF 将在事务结束之前保留对受影响行的锁定。 尽管某些更新可能会发生,例如创建新行,但这可以防止对正在读取或更新的数据进行大多数冲突的更改。 这是悲观并发。

READ_COMMITTED_SNAPSHOT_ON 可获取数据的快照。 然后,在该快照上完成更新,允许其他连接查询原始数据。 在事务结束时,数据的当前状态与快照进行比较。 如果数据相同,则提交事务。 如果数据不同,则回滚事务。

若要将隔离级别更改为 READ_COMMITTED_SNAPSHOT_ON,请发出以下命令:

ALTER DATABASE *db_name* SET READ_COMMITTED_SNAPSHOT ON;

若要将隔离级别更改为 READ_COMMITTED_SNAPSHOT_OFF,请发出以下命令:

ALTER DATABASE *db_name* SET READ_COMMITTED_SNAPSHOT OFF;

如果数据库已更改为启用读取已提交快照,则使用默认的读取已提交隔离级别的任何事务都将使用乐观锁定。

注释

快照隔离仅针对读取已提交事务发生。 使用其他隔离级别的事务不会受到影响。