SQL事务的隔离级别
SQL4种隔离级别的定义
隔离级别的定义涉及到三种现象,读脏数据,不可重复读,幻读。定义来自postgresql的最新文档
dirty read A transaction reads data written by a concurrent uncommitted transaction.
nonrepeatable read A transaction re-reads data it has previously read and finds that data has been modified by another transaction (that committed since the initial read).
phantom read A transaction re-executes a query returning a set of rows that satisfy a search condition and finds that the set of rows satisfying the condition has changed due to another recently-committed transaction.
The four transaction isolation levels and the corresponding behaviors are described in Table 13-1.
Isolation LevelDirty ReadNonrepeatable ReadPhantom Read| Read uncommitted | Possible | Possible | Possible |
Note: Prior to PostgreSQL version 9.1, a request for the Serializable transaction isolation level provided exactly the same behavior describedhere. To retain the legacy Serializable behavior, Repeatable Read should now be requested.
注意:在9.1之前的版本,这个隔离级别就是最高级别了。
Serializable Isolation Level前面说了,PG9.1的Repeatable Read Level其实就满足SQL规范的Serializable级别了。那么这个级别是什么呢?
我们先来看一个例子,看看Serializable和真正串行执行事务的区别。
这个级别以及是SQL规范的最高级别了,但是它还是不能等价于真正的串行化(一个事务完成了另一个事务才能开始),比如下面的例子:
class | value
------+------
1 | 10
1 | 20
2 | 100
2 | 200
事务B:SELECT SUM(value) FROM mytab WHERE class = 1 把这个值以class=2插入
事务A:SELECT SUM(value) FROM mytab WHERE class = 2; 把这个值以class=1插入
先解释一下这个两个事务在干什么:多个事务协作计算这个表格value的值——事务A计算class=1的value和,事务B计算class=2,然后将结果以对方的class保持下来,一般对方可以方便的
求和。
如果以上面的隔离级别,也就是SQL规范的Serializable级别,那么两个事务都能提交,并且它们的结果都是300;而串行的结果呢?至少一个应该得到330
因此PG9.1的Serializable是真正的串行隔离级别,如果A插入(2,30),那么事务B的select或者insert都会出错,强迫回滚事务:
ERROR: could not serialize access due to read/write dependencies among transactions
这是用户再次重试事务B,它读到的就是330了。
这个级别需要使用谓词锁(Predicate Lock),它会锁定这个事务里用到过的记录,它会同时使用细粒度的tuple locks和粗粒度的page locks,并且不会造成block和死锁,但是它需要跟踪
事务用过的记录,所以还是比上一个级别慢的。另外如果是只读事务的话,那么它如果发现后面的逻辑不依赖于某些锁定的对象的话,它可能提前释放这些对象。所以知道自己不会修改,
那么最好告诉PG。
To be continued.