加入收藏 | 设为首页 | 会员中心 | 我要投稿 衡阳站长网 (https://www.0734zz.cn/)- 数据集成、设备管理、备份、数据加密、智能搜索!
当前位置: 首页 > 站长学院 > MySql教程 > 正文

超详细的PG事务隔离级别总结,值得收藏

发布时间:2019-08-06 04:06:08 所属栏目:MySql教程 来源:波波说运维
导读:今天主要介绍一下PG的事务隔离,事务隔离和锁机制是息息相关的,希望大家这两块都可以掌握。下面先看下SQL标准的四种隔离级别。 四种隔离级别 SQL标准定义了四种隔离级别。最严格的是可序列化,在标准中用了一整段来定义它,其中说到一组可序列化事务的任

这个级别与读已提交不同之处在于,一个可重复读事务中的查询看到 事务中第一个非事务控制语句开始时的一个快照, 而不是事务中当前语句开始时的快照。 因此,在一个单一事务中的后续SELECT 命令看到的是相同的数据(就是我前面说的一个事务两个update那种情况),即它们看不到其他事务在本事务启动后提交的修改。

使用这个级别的应用必须准备好由于序列化失败而重试事务。

UPDATE、DELETE、SELECT FOR UPDATE和SELECT FOR SHARE命令在搜索目标行时的行为和SELECT一样: 它们将只找到在事务开始时已经被提交的行。 不过,在被找到时,这样的目标行可能已经被其它并发事务更新(或删除或锁住)。在这种情况下, 可重复读事务将等待第一个更新事务提交或者回滚(如果它还在进行中)。 如果第一个更新事务回滚,那么它的作用将被忽略并且可重复读事务可以继续更新最初发现的行。 但是如果第一个更新事务提交(并且实际更新或删除该行,而不是只锁住它),则可重复读事务将回滚并带有如下消息

  1. ERROR: could not serialize access due to concurrent update 

因为一个可重复读事务无法修改或者锁住被其他在可重复读事务开始之后的事务改变的行。

当一个应用接收到这个错误消息,它应该中断当前事务并且从开头重试整个事务。在第二次执行中,该事务将见到作为其初始数据库视图一部分的之前提交的改变,这样在使用行的新版本作为新事务更新的起点时就不会有逻辑冲突。

注意只有更新事务可能需要被重试;只读事务将永远不会有序列化冲突。

可重复读模式提供了一种严格的保证,在其中每一个事务看到数据库的一个完全稳定的视图。不过,这个视图并不需要总是和同一级别上并发事务的某些序列化(一次一个)执行保持一致。例如,即使这个级别上的一个只读事务可能看到一个控制记录被更新,这显示一个批处理已经被完成但是不能看见作为该批处理的逻辑组成部分的一个细节记录,因为它读取空值记录的一个较早的版本。

3. 可序列化隔离级别

可序列化隔离级别提供了最严格的事务隔离。这个级别为所有已提交事务模拟序列事务执行;就好像事务被按照序列一个接着另一个被执行,而不是并行地被执行。

超详细的PG事务隔离级别总结,值得收藏

但是,和可重复读级别相似,使用这个级别的应用必须准备好因为序列化失败而重试事务。事实上,这个给力级别完全像可重复读一样地工作,除了它会监视一些条件,这些条件可能导致一个可序列化事务的并发集合的执行产生的行为与这些事务所有可能的序列化(一次一个)执行不一致。这种监控不会引入超出可重复读之外的阻塞,但是监控会产生一些负荷,并且对那些可能导致序列化异常的条件的检测将触发一次序列化失败。

例如,考虑一个表mytab,它初始时包含:

  1. class | value 
  2. ------+------- 
  3. 1 | 10 
  4. 1 | 20 
  5. 2 | 100 
  6. 2 | 200 

假设可序列化事务 A 计算:

  1. SELECT SUM(value) FROM mytab WHERE class = 1; 

并且接着把结果(3)作为一个新行的value插入,新行的class = 2。同时,可序列化事务 B 计算:

  1. SELECT SUM(value) FROM mytab WHERE class = 2; 

并得到结果 300,它会将其与class = 1插入到一个新行中。然后两个事务都尝试提交。如果其中一个事务运行在可重复读隔离级别,两者都被允许提交;但是由于没有执行的序列化顺序能在结果上一致,使用可序列化事务将允许一个事务提交并且将回滚另一个并伴有这个消息:

  1. ERROR: could not serialize access due to read/write dependencies among transactions 

这是因为,如果 A 在 B 之前执行,B 将计算得到合计值 330 而不是 300,而且相似地另一种顺序将导致 A 计算出一个不同的合计值。

当依赖可序列化事务来阻止异常时,重要的一点是任何从一个持久化用户表读出数据都不被认为是有效的,直到读它的事务已经成功提交为止。即便是对只读事务也是如此,除了在一个可推迟的只读事务中读取的数据是读出以后立刻有效的,因为这样的一个事务在开始读取任何数据之前会等待,直到它能获得一个快照保证来避免这种问题为止。在所有其他情况下,应用不能依靠在一个后来被中断的事务中读取的结果;相反,它们应当重试事务直到它成功。

要保证真正的可序列化,PostgreSQL使用了谓词锁,这意味着它会保持锁,这些锁让它能够判断在它先运行的情况下,什么时候一个写操作会对一个并发事务中之前读取的结果产生影响。在PostgreSQL中,这些锁并不导致任何阻塞,并且因此不会导致一个死锁。它们被用来标识和标志并发可序列化事务之间的依赖性,这些事务的组合可能导致序列化异常。相反,一个想要保证数据一致性的读已提交或可重复读事务可能需要拿走一个在整个表上的锁,这可能阻塞其他尝试使用该表的用户,或者它可能会使用不仅会阻塞其他事务还会导致磁盘访问的SELECT FOR UPDATE或SELECT FOR SHARE。

像大部分其他数据库系统,PostgreSQL中的谓词锁基于被一个事务真正访问的数据。这些谓词锁将显示在pg_locks系统视图中,它们的mode为SIReadLock。这种在一个查询执行期间获得的特别的锁将依赖于该查询所使用的计划,并且在事务过程中多个细粒度锁(如元组锁)可能和少量粗粒度锁(如页面锁)相结合来防止耗尽用于跟踪锁的内存。如果一个READ ONLY事务检测到不会有导致序列化异常的冲突发生,它可以在完成前释放其 SIRead 锁。事实上,READ ONLY事务将常常可以在启动时确立这一事实并避免拿到任何谓词锁。如果你显式地请求一个SERIALIZABLE READ ONLY DEFERRABLE事务,它将阻塞直到它能够确立这一事实(这是唯一一种可序列化事务阻塞但可重复读事务不阻塞的情况)。在另一方面,SIRead 锁常常需要被保持到事务提交之后,直到重叠的读写事务完成。

(编辑:衡阳站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读