事务隔离级别 (ODBC)

“事务隔离级别”是事务隔离成功程度的度量值。 具体而言,事务隔离级别由存在或缺少以下现象定义:

  • 脏读当事务读取尚未提交的数据时,将发生“脏读”。 例如,假设事务 1 更新行。 事务 2 在事务 1 提交更新之前读取更新的行。 如果事务 1 回滚更改,事务 2 将读取被视为从未存在过的数据。

  • 不可重复读当事务读取同一行两次但每次获取不同的数据时,将发生“不可重复读”。 例如,假设事务 1 读取行。 事务 2 更新或删除该行并提交更新或删除。 如果事务 1 重新读取该行,将检索到不同的行值或发现该行已被删除。

  • 虚拟“虚拟”是匹配搜索条件但最初看不到的行。 例如,假设事务 1 读取一组满足某些搜索条件的行。 事务 2 生成与事务 1 的搜索条件匹配的新行(通过更新或插入)。 如果事务 1 重新执行读取行的语句,将获取一组不同的行。

根据这些现象定义四个事务隔离级别(由 SQL-92 定义)。 下表中,“X”标记可能发生的每个现象。

事务隔离级别 脏读 不可重复读 虚拟
未提交读 X X X
已提交读 -- X X
可重复读 -- -- X
可序列化 -- -- --

下表描述了 DBMS 可能实现事务隔离级别的简单方法。

重要

大多数 DBMS 使用比这些方案更复杂的方案来提高并发性。 这些示例只用于说明。 特别是,ODBC 不规定特定 DBMS 如何相互隔离事务。

事务隔离 可能的实现
未提交读 事务不会彼此隔离。 如果 DBMS 支持其他事务隔离级别,将忽略用于实现这些级别的任何机制。 因此,不会对其他事务产生负面影响,在“读取未提交”级别运行的事务通常是只读的。
已提交读 事务等待,直到其他事务写入锁定的行被解除锁定;这可以防止该事务读取任何“脏”数据。

事务对当前行保留读取锁(如果只读取行)或写入锁(如果更新或删除行),以防止其他事务更新或删除当前行。 事务在离开当前行时释放读取锁。 事务保留写入锁,直到提交或回滚。
可重复读 事务等待,直到其他事务写入锁定的行被解除锁定;这可以防止该事务读取任何“脏”数据。

事务在其返回给应用程序的所有行上保留读取锁,在其插入、更新或删除的所有行上保留写入锁。 例如,如果事务包含 SQL 语句 SELECT * FROM Orders,则当应用程序提取行时,事务读取锁定行。 如果事务包含 SQL 语句 DELETE FROM Orders WHERE Status = 'CLOSED',则事务在删除行时对其执行写入锁定。

由于其他事务无法更新或删除这些行,因此当前事务可避免任何不可重复读。 事务在提交或回滚时释放其锁定。
可序列化 事务等待,直到其他事务写入锁定的行被解除锁定;这可以防止该事务读取任何“脏”数据。

事务对其影响的行范围保留读取锁(如果只读取行)或写入锁(如果可以更新或删除行)。 例如,如果事务包含 SQL 语句 SELECT * FROM Orders,则范围是整个 Orders 表;事务读取锁定该表,不允许插入任何新行。 如果事务包含 SQL 语句 DELETE FROM Orders WHERE Status = 'CLOSED',则范围是状态为“已关闭”的所有行;事务写入锁定 Orders 表中处于“已关闭”状态的所有行,并且不允许插入或更新任何行,使生成的行具有“已关闭”状态。

由于其他事务无法更新或删除范围中的行,因此当前事务可避免任何不可重复读。 由于其他事务无法在范围中插入任何行,因此当前事务可避免任何虚拟。 事务在提交或回滚时释放其锁定。

请务必注意,事务隔离级别不会影响事务看到自身更改的能力;事务始终可以看到其所做的任何更改。 例如,事务可能包含两个 UPDATE 语句,第一个语句将所有员工的薪酬提高 10%,第二个语句将任何员工的薪酬设置为该金额的上限。 这作为单个事务是成功的,因为第二个 UPDATE 语句可以看到第一个语句的结果。