在SQL的标准中事物隔离级别分为如下四种:
1. 读未提交(Read uncommitted)
2. 读已提交(Read committed)
3. 可重复读(Repeatable read)
4. 可串行化(Serializable)
然而PostgreSQL在9.1以前的版本中只是实现了其中两种,即读已提交和可串行化,若是在实际应用中选择了另外两种,那么PostgreSQL 将会自动向更严格的隔离级别调整。在PostgreSQL v9.1的版本中提供了三种实现方式,即在原有的基础上增长了可重复读。在这篇博客中咱们将只是针对2)和4)进行说明和比较,由于在9.1中,3)和 4)的差异也是很是小的。 并发
读已提交 | 可串行化 | |
PostgreSQL缺省隔离级别 | 是 | 否 |
其它事物未提交数据是否可见 | 不可见 | 不可见 |
执行效率 | 高 | 低 |
适用场景 | 简单SQL逻辑,若是SQL语句中含有嵌套查询,那么在屡次SQL查询中将极有可能得到不一样版本的数据。 | 复杂SQL逻辑,特别是带有嵌套的查询比较适用。 |
SELECT查询一致性时间点 | 从该SELECT查询开始执行时,在此查询执行期间,任何其它并发事物针对该查询结果集的数据操做都将不会被本次查询读到,即本次查询获取的数据版本是与查询开始执行时的数据版本相一致。 | 从该SELECT查询所在事物开始时,在此查询执行期间,任何其它并发事物针对该查询结果集的数据操做都将不会被本次查询读到,即本次查询获取的数据版本是与查询所在事物开始时的数据版本相一致。 |
同事物内的数据操做是否可见 | 好比在同一个事物内存在update和select操做,即便当前事物还没有提交,update所做的修改,在当前事物后面的select中依然可见。 | 和读已提交相同。 |
同事物内屡次相同的select所见的数据是否相同 | 不一样,因为该级别select的一致性时间点是该查询开始执行时,而屡次查询的时间点将确定不相同,若是在第一次查询开始到第二次查询开始之间,其它的并发事物修改并提交或当前事物仅修改了查询将要获取的数据,那么这些数据操做的结果将会在第二个查询中有所体现。 | 须要分两步来讲,对于同一事物内的修改若是发 生在两次查询语句之间,那么第二个查询将会看到这些修改的结果。然而对于其它并发事物的修改,将不会形成任何影响,即两次select的结果是相同的。原 因显而易见,该隔离级别的select一致性时间点是与事物开始时相一致的。 |
相同行数据的修改 | 若是此时两个并发事物在修改同一行数据,先修 改的事物将会给该行加行级锁,另一个事物将进入等待状态,直到第一个事物操做该行结束。那么假若第一个针对该行的修改操做最终被其事物回滚,第二个修改 操做在结束等待后,将直接修改该数据。然而若是第一个操做是被正常提交的话,那么就须要进一步判断该操做的类型,若是是删除(delete)该行,第二个 修改操做将直接被忽略。若是是update该行的记录,第二个修改操做则须要从新评估该行是否依然符合以前定义的修改条件。 | 和读已提交隔离级别的机制基本相同,只是在第 一个修改操做提交后,第二个操做将再也不区分以前的修改是delete仍是update,而是直接并返回下面信息:Error: Can't serialize access due to concurrent update. 这是由于一个可串行化的事务在可串行化事务开始以后不能更改或者锁住被其余事务更改过的行。所以,当应用收到这样的错误信息时,它应该退出当前的事务而后 从头开始从新进行整个事务。在应用程序中,也应该有必要的代码来专门处理该类错误。 |
最后须要说明的是,在绝大多数的状况下,读已提交级别都可适用,并且该级别的并发效率更高。只有在比较特殊的状况下,才手工将当前的事物隔离级别调整为可串行化或可重复读。 spa