1 介绍
具有基本知识的DBA都知道,PostgreSQL在控制数据的一致性是通过使用一种多版本模型来维护的,也就是常说的多版本并发控制MVCC。这也就意味着每一个sql语句看到的都只是一小段时间的数据库快照,或者称为版本,而并不关心底层的数据文件当中的当前状态。这样带来的好处就是保护每一个会话中的事务不受到其他会话的影响,提供了非常好的事务隔离机制。MVCC并发控制模型相对于锁机制的优点在于,查询数据的锁请求与写数据的锁请求并不冲突,所以,读不会阻塞写,写也不会阻塞读。
2 事务隔离
其实说起事务隔离,可能偏向于理论上一些,但是对于数DBA人员来说,这个需要牢牢掌握,因为很多时候在排查异常问题的时候,需要分析每一个sql、每一个事务都对数据库进行了哪些操作,为什么会导致数据不一致的原因等等。
sql标准定义了四种隔离级别:读未提交、读已提交、读可重复、可序列化。四种关系层层递进,越来越严格。
-
读未提交 Read uncommitted
解释就是一个事务读到了另一个事务未提交的数据,一旦另一个事务回滚了,那么读到的数据就是有问题的。这种现象就是脏读了。 -
读已提交 Read committed
读已经提交的数据能够解决脏读的问题,因为这个事务需要等待另一个事务提交后才能读取数据。但是该级别有一个问题,重复读的时候可能会产生不同的数据,这是因为该事务读取的两次过程中,这些数据并没有锁住 ,还是可以处于能够修改(update和delete)的。该级别是postgresql默认的级别。 -
读可重复 Repeatable read
该级别解决了读已提交的不可重复读的问题,在事务开启的时候,不能再修改操作了,直到该事务提交。该级别是mysql,Oracle,sql server默认的级别。但是在该级别,还是会出现幻读的问题,幻读和可重复读非常类似,都是两次查询的结果不一致,可以这么理解,一个事务在插入一个检查过不存在的记录时,发现数据已经存在了,之前检查的结果就像幻觉一样,这是因为已经插入了新的数据导致的。区别需要从机制来看,读某一行数据,会给行加行排他锁,事务无法修改数据,重复读就不会出现数据不一致的问题,但是并没有加表锁,还是可以insert数据的。这就导致了后面查询数据变多了
。mysql会出现幻读,pg不会。
幻读举例说明如下:
- 序列化 Serializable
序列化是最高的事务隔离级别,在该级别下,事务是按照串行化的顺序执行,可以避免脏读,重复读,幻读。但是可想而知,所有事务都是按照串行化顺序执行,那怎么保证高并发呢?这种数据库必然性能非常低下,几乎没有数据库会达到这种级别。
下表概括了SQL标准和PG实现的事务隔离级别中的描述
隔离级别 | 脏读 | 不可重复读 | 幻读 | 序列化异常 |
---|---|---|---|---|
读未提交 | 允许,但不在PG中 | 可能 | 可能 | 可能 |
读已提交 | 不可能 | 可能 | 可能 | 可能 |
可重复读 | 不可能 | 不可能 | 允许,但不在PG中 | 可能 |
可序列化 | 不可能 | 不可能 | 不可能 | 不可能 |
3 总结
了解事务隔离对DBA非常重要,DBA可以根据业务的需求更改数据库的默认隔离级别,预期达到性能的最大化。