SQL 隔离等级与隔离策略

563 阅读4分钟

隔离等级与隔离策略

严格的隔离级别直接影响并发性。因此,允许并发处理的隔离要求经常被放宽。

ISO/ANSI SQL 标准定义了四个隔离级别,它们提供不同的和递增的隔离级别。

这四个级别如下:

  • Read Uncommitted(读取未提交)

  • Read Committed (读取已提交)

  • Repeatable Read (可重复读取)

  • Serializable (可序列化)

此外,没有隔离或完全混乱可以被视为第五级隔离。

使用示例可以清楚地解释隔离级别。参考一个简单的数据集合(或 RDBMS 世界中的表) ,

如表所示。

IDNAMEOCCUPATIONLOCATION(CITY) 1
1James JoyceAuthorNew York 2
2Hari KrishnaDeveloperSan Francisco 3
3Eric ChenEntrepreneurBoston

现在,假设有两个独立的事务,事务1和事务2并发地操作这个数据集:

1.事务1读取集合中的所有三个数据点。

2.然后,事务2使用 id 2读取数据点,并将该数据项的 Location (City)属性从“ San Francisco”更新到“ San Jose”但是,它不提交更改。

3.事务1重新读取集合中的所有三个数据点。 事务2回滚在步骤2中执行的更新.根据隔离级别的不同,结果会有所不同。

如果隔离级别设置为 Read Uncommit 则事务1将在步骤3中看到事务2(从步骤2开始)更新的但未提交的更改。与步骤4一样,这种未提交的更改可以回滚,因此,这种读操作被恰当地称为脏读操作。

如果隔离级别稍微严格一些,并且设置为下一个级别 Read Commit

操作 1在重新读取步骤3中的数据时不会看到未提交的更改。


现在,交换步骤3和4以及事务2提交更新的情况。新的步骤如下:

  1. 事务1读取集合中的所有三个数据点。

2.然后,事务2使用 id 2读取数据点,并将该数据项的 Location (City) 属性从“ San Francisco”更新到“ San Jose”但是,它还没有提交更改。

3.事务2提交在步骤2中执行的更新。

4.事务1重新读取集合中的所有三个数据点。

读取未提交隔离级别不受步骤更改的影响。这个级别允许脏读操作,所以显然提交的更新可以毫无困难地读取。但是,读取提交的行为不同。

现在,因为已经在步骤3中提交了更改,所以事务1读取步骤4中更新的数据。步骤1和步骤4的读取不相同,因此这是一种不可重复读取的情况。

当隔离级别升级到可重复读取时,步骤1和步骤4中的读取是相同的。也就是说,事务1与事务2中提交的更新隔离开来,而它们都是并发进行的。

尽管在这个级别上保证了可重复读取,但是可能会发生相关记录的插入和删除。这可能导致在后续读取中包含和排除数据项,通常称为幻像读取


要通过幻像读取的情况下参考一个新的步骤序列如下:

1.事务1运行一个范围查询,要求所有 id 在1到5之间的数据项(包括这两个数据项)。因为集合中最初有三个数据点,并且都满足条件,所以返回所有三个数据点。

2.然后,事务2插入一个具有以下值的新数据项:

{ Id = 4,Name = ‘ Jane Watson’,Occupation = ‘ Chef’,Location (City) = ‘ Atlanta’}

3.事务2提交步骤2.4中插入的数据。

现在,将隔离设置为可重复读级别后,在步骤1和步骤4中返回给事务1的数据集就不一样了。

步骤4除了原来的三个数据点之外,还查看 id 为4的数据项。

为了避免幻象读取,需要涉及读取的范围锁定,并使用最高级别的隔离 Serializer。序列化这个术语意味着事务的顺序处理或序列排序,但并不总是这样。

但是,当其中一个并发事务处理数据范围时,它确实阻塞了其他并发事务。在一些数据库中,快照隔离被用来实现可序列化的隔离。这样的数据库在启动时提供带有快照的事务,并且只有在快照后没有任何更改时才允许提交。

使用更高的隔离级别增加了饥饿和死锁的可能性。当一个事务将其他事务的资源锁定不让其他事务使用时,就会发生; 当两个并发事务相互等待完成并释放一个资源时,就会发生死锁。


本文正在参加「金石计划 . 瓜分6万现金大奖」