SQL事务的隔离级别(一)

2014-11-24 08:36:14 ? 作者: ? 浏览: 7

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.
www.2cto.com
Isolation LevelDirty ReadNonrepeatable ReadPhantom Read| Read uncommitted | Possible | Possible | Possible |
Read committed Not possible Possible Possible
Repeatable read Not possible Not possible Possible
Serializable Not possible Not possible Not possible
下面我举例来说明这三种现象和4种隔离级别的区别。
==mytable==
id age name
1 20 zhang
2 22 li
3 23 wang
读脏数据
事务A select * from mytable where id=1 事务B update mytable set age=age+1 where id=1 rollback
如果隔离级别是Read Uncommitted,那么A可能读到的age是21岁,虽然21这个值只是一个临时的值,事务B最终回归了它。
如果能避免这种现象,那么隔离级别就至少是Read committed了。
不可重复读
事务A select * from mytable where id=1 select * from mytable where id=1 事务B update mytable set age=age+1
www.2cto.com
如果隔离级别不是Repeatable read,那么A第一次读的值可能是20,第二次变成了21
如果能避免这种现象,那么隔离级别就至少是Repeatable read
幻读
事务A select * from mytable where age<23 select * from mytable where age<23 事务B insert into mytable values(4, 21,'zhou')
如果能避免这种现象就是Serializable。
注意上面的例子,可重复读但不能幻读的情况:比如在基于锁的实现里,可能只锁定了age为20和22的行,但并没有锁定范围,那么可以插入age为21的新行,这是可以保证可重复读的。注意不可重复读和幻读的定义的文字细节:
A transaction re-reads data it has previously read and finds that data has been modified by another transaction
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.
www.2cto.com
很多资料没有把这两种分清楚。那上面的例子来说,A select * from mytable where age<23 这个query应该分为两步:首先找到age<23的记录,然后读取这些记录。
可重复读指的是:我在同一个事务里两次读取这些记录的值是相同的,但它不能避免幻读,因为下次执行同一个查询时,满足条件的记录可能变多了。
举个例子: 事务A select id from mytable where age<23 对于满足上面要求的id,找到这个id对应的name。
这个例子在现实中不太可能发生,不过可以清楚的解释第二和第三中隔离级别的区别。这个事务其实就是找到年龄小于23的人的名字。
如果只要满足第二种隔离级别,那么这个事务的结果就是我想要的结果。在这个事务的过程中,可能修改了zhang的名字,但是我拿到的还是zhang
但是如果它不满足第三种隔离级别,那么可能再次执行这条语句会多出一个人来。而如果满足第三种隔离级别,那么select出来的结果是不变的。
不过很多 数据库系统的实现里都使用了比较强的实现,所以也不必特意强调它们的区别。
真正串行
两个事务的结果和一个一个运行完全一样。具体的例子会在下面Postgresql的说明里提到。
这个SQL 92 标准并没有定义,也就是说,即使是Serializable级别的,也可能不能保证这个要求,不过PostgreSQL是能够做到这点的。
www.2cto.com
PostgreSQL的隔离级别
注意:我这里说的是最新开发版本9.1的情况,9.1之前的版本只能到Serializable级别的,而不能到“真正串行”的级别。
Read Committed Isolation Level
这是PG的默认隔离级别,保证不会读到脏数据,PG认为这个级别能够满足一般的事务需求,而且非常高效。这种级别下,select只能看到执行前这一瞬间前提交的修改,在它执行过程中的提交是看不到的。(当然,它所在事务之前的修改即使未提交也是对它可见的)。如果这个select是update,delete等语句的条件,那么它select结果也是这样,如果在它修改的时候,发现有其它事务在做修改(那么这个事务至少删除或者锁定了某些对象,否则当前更新就在它之前),那么它会等其它事务完成,如果其它事务roll back了,它会继续更新;如果其它事务commit了,那么它会在其它事务的结果的基础上更新------如果前面的事务把它删除了,那么它就忽略这条记录;如果前面的事务修改了它,那么它会尝试从新判断这条记录是否满足条件。这是比较常见的,如果别的事务把记录修改了,那么原来满足条件的记录现在可能不满足了。
比如银
-->

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: