Appearance
SQL Server 设置事务隔离级别
1. 语法
SQL
-- Syntax for SQL Server and Azure SQL Database
SET TRANSACTION ISOLATION LEVEL
{ READ UNCOMMITTED
| READ COMMITTED
| REPEATABLE READ
| SNAPSHOT
| SERIALIZABLE
}1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
示例:
SQL
-- Syntax for Azure Synapse Analytics and Parallel Data Warehouse
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED1
2
3
2
3
Note
选择事务隔离级别不影响为保护数据修改而获取的锁。无论为事务设置了什么隔离级别,事务总是对其修改的任何数据获得独占锁,并保持该锁直到事务完成。此外,在 READ_COMMITTED 隔离级别进行的更新使用所选数据行的更新锁,而在 SNAPSHOT 隔离级别进行更新则使用行版本来选择要更新的行。对于读取操作,事务隔离级别主要定义了对其它事务所做修改的影响的保护级别。有关详细信息,请参阅事务锁和行版本控制指南。
2. 参数
2.1. READ UNCOMMITTED
指定语句可以读取已被其它事务修改但尚未提交的行。
在 READ UNCOMMITTED 级别运行的事务不会发出共享锁,以防止其它事务修改当前事务已读取的数据。READ UNCOMMITTED 事务也不会被排他锁阻止,排他锁会阻止当前事务读取已修改但未被其它事务提交的行。设置此选项后,可以读取未提交的修改,这称为脏读。数据中的值可以被修改,行可以在事务结束前出现或消失在数据集中。此选项与对事务中所有 SELECT 语句中的所有表设置 NOLOCK 的效果相同。这是隔离级别中限制最小的。
在 SQL Server 中,您还可以使用以下任一项来最大限度地减少锁的争用,同时保护事务不受脏读影响:
- 在将
READ_COMMITTED_SNAPSHOT数据库选项设置为ON时的 READ COMMITTED 隔离级别; - 关于 SNAPSHOT 隔离级别,详细信息请参阅 SQL Server 中的快照隔离;
2.2. READ COMMITTED(默认值)
指定语句不能读取其它事务已修改但未提交的数据,这可以防止脏读。在当前事务中的每条语句之间,数据可以被其它事务修改,从而导致不可重复读、幻读。此选项是 SQL Server 的默认选项。
READ COMMITTED 的行为取决于 READ_COMMITTED_SNAPSHOT 数据库选项的设置:
- 如果
READ_COMMITTED_SNAPSHOT设置为OFF(SQL Server 的默认值),则数据库引擎使用共享锁来防止其它事务在当前事务运行读取操作时修改行。共享锁还阻止语句读取由其它事务修改的行,直到其它事务完成。共享锁类型决定何时释放,在处理下一行之前释放行锁,读取下一页时释放页锁,语句完成时释放表锁; - 如果
READ_COMMITTED_SNAPSHOT设置为ON(Azure SQL Database 的默认值),则数据库引擎使用行版本控制为每条语句提供一个事务一致的数据快照,该快照与语句开始时的数据快照相同。锁不用于保护数据免受其它事务的更新;
当 READ_COMMITTED_SNAPSHOT 数据库选项设置为 ON 时,您可以使用 READCOMMITTEDLOCK 表提示为 READ COMMITTED 隔离级别上运行的事务中的各语句请求共享锁,而不是行版本控制。
2.3. REPEATABLE READ
指定语句不能读取其它事务已修改但未提交的数据,并且在当前事务完成之前,任何其它事务都不能修改当前事务已读取的数据。
共享锁放置在事务中每个语句读取的所有数据上,并一直保持到事务完成。这将防止其它事务修改当前事务已读取的任何行。其它事务可以插入与当前事务发出的语句的搜索条件匹配的新行。如果当前事务然后重试该语句,它将检索新行,这将导致幻读。由于共享锁保存到事务结束时,而不是在每个语句结束时释放,因此并发性低于默认的 READ COMMITTED 隔离级别。仅在必要时使用此选项。
2.4. SNAPSHOT
指定事务中任何语句读取的数据将是事务开始时存在的数据的事务一致版本。事务只能识别在事务开始之前提交的数据修改。当前事务开始后其他事务所做的数据修改对当前事务中执行的语句不可见。其效果就好像事务中的语句获取了事务开始时已提交数据的快照。
除非正在恢复数据库,否则 SNAPSHOT 事务在读取数据时不会请求锁。SNAPSHOT 事务读取数据不会阻止其他事务写入数据。写入数据的事务不会阻止 SNAPSHOT 事务读取数据。
在数据库恢复的回滚阶段,如果尝试读取由其他正在回滚的事务锁定的数据,则 SNAPSHOT 事务将请求一个锁。在事务完成回滚之前,SNAPSHOT 事务会一直被阻塞。当事务取得授权之后,便会立即释放锁。
在启动使用 SNAPSHOT 隔离级别的事务之前,必须将 ALLOW_SNAPSHOT_ISOLATION 数据库选项设置为 ON。如果使用 SNAPSHOT 隔离级别的事务访问多个数据库中的数据,则必须在每个数据库中将 ALLOW_SNAPSHOT_ISOLATION 设置为 ON。
不能将通过其他隔离级别开始的事务设置为 SNAPSHOT 隔离级别,否则将导致事务中止。如果事务以 SNAPSHOT 隔离级别开始,则可以将其更改为另一个隔离级别,然后返回 SNAPSHOT。事务在第一次访问数据时开始。
在 SNAPSHOT 隔离级别下运行的事务可以查看由该事务所做的更改。例如,如果事务对表执行 UPDATE,然后对同一个表执行 SELECT 语句,则修改后的数据将包含在结果集中。
2.5. SERIALIZABLE
指定下列内容:
- 语句不能读取已由其他事务修改但尚未提交的数据;
- 任何其他事务都不能在当前事务完成之前修改由当前事务读取的数据;
- 在当前事务完成之前,其他事务不能使用当前事务中任何语句读取的键值插入新行;
范围锁处于与事务中执行的每个语句的搜索条件相匹配的键值范围之内。这样可以阻止其他事务更新或插入任何行,从而限定当前事务所执行的任何语句。这意味着如果再次执行事务中的任何语句,则这些语句便会读取同一组行。在事务完成之前将一直保持范围锁。这是限制最多的隔离级别,因为它锁定了键的整个范围,并在事务完成之前一直保持范围锁。因为并发级别较低,所以应只在必要时才使用该选项。该选项的作用与在事务内所有 SELECT 语句中的所有表上设置 HOLDLOCK 相同。