最近在读PostgreSQL的官方文档,PostgreSQL支持SQL标准定义的读未提交、读已提交、可重复读、可串行化这4个事务隔离级别。而内部其实只有读已提交,可重复读和可串行化这3种独立的隔离级别,所以文档里只说明了这3种隔离级别。问题是文档里的说明比较生硬,看完似懂非懂。有没有哪位大神帮我通俗的解释一下这4个事务隔离级别啊?
最近在读PostgreSQL的官方文档,PostgreSQL支持SQL标准定义的读未提交、读已提交、可重复读、可串行化这4个事务隔离级别。而内部其实只有读已提交,可重复读和可串行化这3种独立的隔离级别,所以文档里只说明了这3种隔离级别。问题是文档里的说明比较生硬,看完似懂非懂。有没有哪位大神帮我通俗的解释一下这4个事务隔离级别啊?
读未提交:事务T在修改数据R之前必须先对其加排它锁,事务结束后释放
读已提交:一级封锁协议+事务T在读取数据R之前必须先对其加共享锁,读取后(事务结束前)释放
可重复读:一级封锁协议+事务T在读取数据R之前必须先对其加共享锁,事务结束后释放
6 回答3.4k 阅读✓ 已解决
4 回答2k 阅读
2 回答2.5k 阅读
1 回答1k 阅读✓ 已解决
2 回答1.5k 阅读
2 回答1.8k 阅读
1 回答1k 阅读✓ 已解决
我认为要理解事务隔离级别,就必须先理解"脏读","不可重复读"和"幻读"这三个现象。因此我会以下表为例直观说明这三种读的具体现象。
这种现象出现在事物间的隔离级别最差的场景下,写事务对一个元组的更新尚未提交时就被另一个事务读到了。如果在一个业务应用中,写事务后面没提交而是回滚了,那么可以预见这个读事务读到的这个未提交的更新在某些业务场景下可能会带来一些困扰。
这种现象比上面的脏读好一点,只有当写事务提交后,这个更新才会被读事务读取到。但是考虑到如上图所示,在同一个事务中的不同时间点意图读取同一个元组却读到了不同的数据,在某些业务场景下可能也会带来一些困扰。
幻读这一现象针对的已不是表中的单一元组而言,而是指读事务在对表中的某个范围多个元组而言的一种现象,引发幻读的写事务对应的操作通常是INSERT或DELETE。如下图所示:
在同一个读事务中,对于同一个过滤条件查询出了不同的结果集,这在某些业务场景下也有可能带来一定的困扰。
上面这些就是关于"脏读","不可重复读"以及"幻读"这三个现象的介绍。除此之外,这边还需要再强调两个注意点:
但事实上,它并非"不可重复读"的例子。因为在会话2中没有开启显式事务,因此两个SELECT语句分属于不同事务。"脏读","不可重复读"以及"幻读"的概念不适用于不同的事务之间的读操作。
理解清楚了以上的这三个"读"的概念后,就可以很容易的理解事务隔离级别了。因为事务隔离级别的设置本质上就意味着让你控制并发事务之间的写事务带来的数据更新的可见性——即,你允许业务中的并发事务之间出现怎样的都现象. 由于"脏读","不可重复读"以及"幻读"的概念是一种层层递进的概念,因此事务隔离级别从"Read Uncommited"到"Serializable"也是一个比一个严格。
需要注意的是,SQL标准中对于这些隔离级别定义中约束的"不允许"现象是强制要求的。数据库厂商在宣称支持某个隔离级别时,必须将上表中对应隔离级别的"不允许"进行实现。但是对于"可能"项则不代表你必须实现成具备某种都现象。在PostgreSQL中,由于其MVCC的实现,
REPEATABLE READ
对于读事务的行为实现也和SERIALIZABLE
一样是不会出现幻读的,而REPEATABLE READ
和SERIALIZABLE
的区别,主要体现在下文所述的对更新操作的约束力度上。此外,需要特别说明一下SERIALIZABLE这个隔离级别对于并发写事务有所约束:
在其他隔离级别中,如果并发的两个事务同时意图对同一个元组进行更新时, 后更新的事务会等待直到先更新的事务提交后在继续执行其更新操作。 但是在SERIALIZABLE的情况下,由于此时事务隔离级别最强,会对有可能对读一致性带来影响的写操作必须按照事务的串行执行。在PG的实现中,这表现为尝试对于同一元组进行更新的并发事务会在等待完先更新的事务提交后自己报个错:
在SERIALIZABLE隔离级别下,对于上图中的两个更新事务若都希望成功,需要保证右边会话的更新操作所属事务的
START TRANSACTION
必须发生在左边会话的更新事务COMMIT
之后。以上,就是关于事务隔离级别的那点儿事,希望我这个回答能够帮题主解惑。