postgresql事务处理与并发控制:
事务是postgresql中的基本工作单元,是用户定义的一个数据库操作序列。这些操作要么全做,要么全不做,是一个不可分割的工作单位。
在postgresql中,事务管理器负责管理事务运行的模块(模块有:锁管理器和日志管理器)
事务管理器是事务系统的中枢,通过接受信息,处理下一步的事务操作。
锁管理器主要提供事务的写阶段并发控制所需的 各种锁,从而保证事务的各种隔离级别。
日志管理器主要记录事务执行的状态和数据的变化过程。
事务开始后,事务中的所有操作都会写到事务日志中。写到日志中的事务一般有两种:一种是针对数据的操作,如插入、修改和删除,这些操作的对象是大量的数据;另一种是针对任务的操作,例如创建索引。当取消这些事务操作时,系统自动执行这种操作的反操作,保证系统的一致性。系统自动生成一个检查点机制。这个检查点周期地检查事务日志,如果在事务日志中,事务全部完成,检查点事务日志中的事务就提交到数据库 中,并且在事务日志中做一个检查点提交表示。如果在事务日志中,事务没有完成,检查点就不会讲事务日志中的事务提交到数据库中,并会在事务日志中做一个检查点未提交的标识。事务的恢复及检查点保证了系统的完整和可恢复。
1、事务的属性
事务是作为单个逻辑工作单元执行的一系列操作。一个逻辑工作单位必须有4个属性,即原子性、一致性、隔离性和持久性属性,简称ACID属性,只有这样才能成为一个事务。
原子性:事务必须是原子工作单元;对于数据修改,要么全都执行,要么全都不执行。
一致性:事务在完成时,必须使所有的数据都保持一致。
隔离性:由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。事务识别数据时数据所处的状态要么是第二个并发事务修改之前的状态,要么是第二个事务修改之后的状态,不会识别中间状态的数据。这称为可串行性,因为它能够重新装载起始数据,并且重播一系列事务,以使数据结束时的状态与原始事务执行的状态相同。
持久性:事务完成之后,对于系统的影响是永久性的。该修改即使出现系统故障也将一直保持。
2、事务块管理的常用语句:
在postgresql里,一个事务是通过把SQL命令用:begin 和 commit命令包围实现的。事务块是指包围在begin 和 commit之间的语句。在postgresql9中,常用的事务块管理语句的含义如下:
start transaction:表示开始一个新的事务块。
begin:表示初始化一个事务块 。
commit:表示提交事务;
rollback:表示事务失败时执行回滚操作。
set transaction:设置当前事务的特性,对后面的事务么有影响。
3、postgresql的并发控制
3.1、脏读:
当一个事务读取的记录时另一个事务的一部分时,如果第一个事务正常完成,就没有什么问题,如果此时另一个事务未完成,就会产生脏读。
3.2、幻读:
当某一数据执行insert 或 delete操作,而该数据行恰好属于某个事务正在读取的范围时,就会发生幻读现象。比如在运行update语句的同时执行insert操作,因为插入了一个新记录行,所以没有锁定,并且能够珍惜。
3.3、不可重复性读取:
如果一个事务不止一次地读取相同的记录,但在两次读取中间有另一个事务刚好修改了数据,则两次读取的数据将出现差异,此时就发生了非重复读取。
3.2、postgresql的事务隔离级别:
《隔离级别》 《脏读》 《幻读》 《不可重复性读取》
读未提交 可能 可能 可能
读已提交 不可能 可能 可能
可重复读 不可能 可能 不可能
可串行读 不可能 不可能 不可能
在postgresql里,可以请求4种可能的事务隔离级别的任意一种。但是在内部,实际上只有两种独立的隔离级别,分别对应:读已提交 和 可串行化。也就是说,如果选择了读未提交的级别,实际上使用的是读已提交。在选择可重复读级别的时候,实际上用的是可串行化,所以实际的隔离级别可能比选择的更严格。postgresql只提供两种隔离级别的原因是:这是把标准的隔离级别与多版本并发控制架构映射相关的唯一合理方法。
postgresql中的两种隔离级别如下:
①:读已提交:
读已提交是postgresql里的默认级别。当一个事务运行在这个隔离级别时,一个select查询只能看到查询开始之前已提交的数据,而无法看到未提交的数据或者在查询执行期间其他事务已经提交的数据。
如果两个事务在对同一组数据进行更新操作,那么第二个事务需要等待第一个事务提交或者更新回滚。如果第一个事务进行提交,系统将重新计算查询条件,符合条件后第二个事务继续进行更新操作;如果第一个事务进行更新回滚,那么他的作业将被忽略,第二个事务将继续更新最初发现的行。
②:可串行化:
可串行化基本提供最严格的事务隔离。这个级别模拟串行的事务执行,就好像事务将一个接着一个地串行(而不是并行)执行。不过,使用这个级别的应用必须准备在串行化失败的时候重新启动事务。
如果两个事务在对同一组数据进行更新操作,那么串行化事务就将等待第一个正在更新的事务提交或回滚。如果第一个事务提交了,那么串行化事务将回滚,从头开始重新进行整个事务;如果第一个事务回滚,那么它的影响将被忽略,这个可串行化的事务就可以在该元祖上进行更新操作。