跨容器事务

跨容器事务可以是隐式或显式的用户事务,包括调用本机编译的存储过程或在内存优化表上进行操作。

在 SQL Server 中,对存储过程的调用不会启动事务。 在自动提交模式下执行本机编译的过程(不在用户事务的上下文中)不被视为跨容器事务。

引用内存优化表的任何解释查询都被视为跨容器事务的一部分,无论是从显式事务还是隐式事务执行,还是在自动提交模式下执行。

单个操作的隔离

每个 SQL Server 事务都有隔离级别。 默认隔离级别为 Read Committed。 若要使用不同的隔离级别,可以使用 SET TRANSACTION ISOLATION LEVEL(Transact-SQL)设置隔离级别。

通常,需要对内存优化表执行操作时采用与对基于磁盘的表操作时不同的隔离级别。 在事务中,可以为语句集合或单个读操作设置不同的隔离级别。

指定单个操作的隔离级别

若要为事务中的一组语句设置不同的隔离级别,可以使用 SET TRANSACTION ISOLATION LEVEL。 以下示例使用可序列化隔离级别作为默认值。 在 t3、t2 和 t1 上的插入和选择作在可重复读取隔离下执行。

set transaction isolation level serializable  
go  
  
begin transaction  
 ......  
  set transaction isolation level repeatable read  
  
  insert t3 select * from t1 join t2 on t1.id=t2.id  
  
  set transaction isolation level serializable  
 ......  
commit  

若要为特定读操作设置与事务默认值不同的隔离级别,可以使用表提示(例如可序列化)。 每个选择对应于读取作,每次更新和每次删除都对应于读取,因为行始终需要读取才能更新或删除。 插入操作没有隔离级别,因为写入在 SQL Server 中总是被隔离的。 在以下示例中,事务的默认隔离级别是读已提交,但表 t1 在可序列化隔离级别下访问,而表 t2 在快照隔离级别下访问。

set transaction isolation level read committed  
go  
  
begin transaction  
 ......  
  
  insert t3 select * from t1 (serializable) join t2 (snapshot) on t1.id=t2.id  
  
  ......  
commit  

单个操作的隔离语义

可序列化事务 T 以完全隔离方式执行。 就好像所有其他事务要么在 T 开始之前已经提交,要么是在 T 提交之后才开始。 当事务中的不同操作具有不同的隔离级别时,情况会变得更加复杂。

SQL Server 中事务隔离级别的一般语义以及锁定的影响,在 SET TRANSACTION ISOLATION LEVEL(Transact-SQL)中进行了解释。

对于具有不同隔离级别的跨容器交易中的不同操作,您需要了解单个读取操作的隔离级别语义。 写入操作始终是隔离的。 不同事务中的写入不能相互影响。

数据读取作返回满足筛选条件的行数。

读取操作作为事务的一部分执行。读取操作的隔离级别可以理解为:

提交状态
提交状态是指是否保证读取的数据已被提交。

(事务性)一致性
一组读取操作的事务性一致性是指是否保证读取的行版本都包含来自完全相同的事务集的更新。

稳定性保证系统向事务 T 提供有关读取数据的信息。
稳定性是指事务的读取是否可重复。 也就是说,如果重复数据读取,是否会返回相同的行和行版本?

某些保证是指事务的逻辑结束时间。 一般情况下,逻辑结束时间是事务提交到数据库的时间。 如果事务访问内存优化表,则逻辑结束时间实际上是验证阶段的开始。 (有关详细信息,请参阅 Transactions in Memory-Optimized Tables 中的交易生命周期讨论。

无论隔离级别如何,事务(T)总是能看到自己的更新。

未提交读取
读取的数据可能既不被提交、也不一致或稳定。 然而,它将包括 T 完成的之前的写入操作。

READ COMMITTED(读已提交)
读取的数据将被提交。

快照
T 在快照隔离下执行的所有读取操作都具有相同的逻辑读取时间,这个时间是事务开始时。 保证数据在逻辑读取时间已提交并保持一致性。 从原始读取时间开始重复读取可以保证返回相同的结果。

可重复读取
保证数据读取在事务的逻辑结束时间之前提交并稳定。

序列 化
REPEATABLE READ 和事务一致性的所有保证,以及避免幽灵读现象,这意味着扫描操作只能返回由事务 T 写入的新增行,而不是由其他事务写入的行。这确保了所有由 T 执行的可序列化读取操作的一致性。

请考虑以下交易:

set transaction isolation level read committed  
go  
  
begin transaction  
  -- remove all rows from t3; the related read operation is performed under read committed   
  -- isolation, as this is the default for the transaction  
  delete from t3  
  
  -- copy the contents from t1 to t3; the read on t1 is performed under the serializable   
  -- isolation level  
  insert t3 select * from t1 (serializable)  
  
  -- compare t3 and t1; note: the result set may not be empty, as rows may have been added   
  -- by other transaction before this select, due to the read committed isolation level  
  select * from t3 except t1  
  
  -- compare t1 and t3; note: the result set is empty, as no rows have been added to t1   
  -- since its contents were copied to t1, due to the serializable isolation level  
  select * from t1 except t3  
commit  

此事务在读取提交隔离下从 t3 删除所有行,在可序列化隔离下将 t1 中的所有行复制到 t3,然后比较 t1 和 t3。 某些行(不在 t1 中)可能已添加到 t3,因为表已清空。 t1没有增加行,因为副本是可序列化的。

尽管事务末尾的 t1 读取是以语法方式读取的,但它实际上是可序列化的,因为之前在事务中执行了相同的读取,在可序列化隔离下执行:可序列化性保证,如果在事务的任意以后点执行读取,则返回相同的行。

跨容器事务和隔离级别

可以将跨容器事务视为具有两个方面:一个是磁盘方面(用于操作基于磁盘的表),一个是内存优化方面(用于操作内存优化表)。 这两端可能有不同的隔离级别。 事实上,每个端的单个读取操作可能具有不同的隔离级别。

如果满足以下条件之一,给定事务 T 的基于磁盘的端达到特定的隔离级别 X:

  • 它以 X 开头。也就是说,会话默认值为 X,要么是因为执行 SET TRANSACTION ISOLATION LEVEL了,要么是 SQL Server 默认值。

  • 在事务期间,默认隔离级别被更改为 X,使用 SET TRANSACTION ISOLATION LEVEL

  • 在隔离级别 X 下,使用语法 WITH (X) 对基于磁盘的表执行读取操作。

在执行 T 期间,如果 T 的内存优化部分在隔离级别 Y 下运行,那么对内存优化表或本机编译存储过程的任何读取操作也会在隔离级别 Y 下执行。

以以下事务为例。 此处,t1 和 t2 是基于磁盘的表,t3 和 t4 是内存优化表。

事务的基于磁盘一侧达到“已提交读”隔离级别,因为该事务从该级别开始。 基于磁盘的方面也达到了可重复读,因为第一个读取操作是在该隔离级别下执行的。 删除操作是在事务末尾使用已提交读取的隔离级别执行的,因此不会引入新的隔离级别。

事务的内存优化端可以达到两个级别之一:如果 condition1 为 true,则它达到可序列化,而如果为 false,则内存优化端仅达到快照隔离。

set transaction isolation level read committed  
go  
  
begin transaction  
  select * from t1 (repeatableread)  
  
  if condition1 begin  
    insert t3 select * from t4 (serializable)  
  end  
  else begin  
    insert t3 select * from t4 (snapshot)  
  end  
  
  delete from t1  
commit  

跨容器事务支持的隔离级别

在跨容器事务中使用的内存优化表上的操作,其隔离级别存在限制。

内存优化表支持隔离级别 SNAPSHOT、REPEATABLE READ 和 SERIALIZABLE。 对于自动提交事务,内存优化表支持隔离级别 READ COMMITTED。

支持以下方案:

  • 读取 UNCOMMITTED、READ COMMITTED 和READ_COMMITTED_SNAPSHOT跨容器事务可以访问 SNAPSHOT、REPEATABLE READ 和 SERIALIZABLE 隔离下的内存优化表。 事务的 READ COMMITTED 保证保留;事务读取的所有行都已提交到数据库。

  • REPEATABLE READ 和 SERIALIZABLE 事务可以在 SNAPSHOT 隔离下访问内存优化表。

只读跨容器事务

SQL Server 中的大多数只读事务在完成提交时回滚。 由于没有对数据库进行提交更改,因此系统只需释放事务使用的资源。 对于基于磁盘的只读事务,该事务占用的所有锁此时都会释放。 对于跨单个本机编译过程执行的只读内存优化事务,不执行验证。

在自动提交模式下,跨容器的只读事务会在事务结束时简单地回滚。 不执行验证。

显式或隐式跨容器的只读事务在提交时执行验证,如果该事务在 REPEATABLE READ 或 SERIALIZABLE 隔离级别下访问内存优化表。 有关验证的详细信息,请参阅 Memory-Optimized 表中的事务 一节中的冲突检测、验证和提交依赖项检查。

另请参阅

了解 Memory-Optimized 表上的事务
Memory-Optimized 表的事务隔离级别指南
Memory-Optimized 表上的事务重试逻辑指南