MySQL社区

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

搜索
查看: 7827|回复: 0
打印 上一主题 下一主题

[PostgreSQL] PostgreSQL并发控制

[复制链接]
跳转到指定楼层
1#
发表于 2009-5-20 15:29:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
http://www.wohedb.com/db_html_doc/sql/sql_9_concurrency.htm
http://www.wohedb.com  中文数据库管理系统

第九章 并发控制


    本章介绍PostgreSQL的并发控制机制。当两个或多个用户同时访问同一个数据行时,需要使用并发控制机制来维护数据的完整性和一致性。



9.1 概述
    PostgreSQL使用的是多版本并发控制机制(Multiversion Concurrency Control, MVCC)。多版本并发控制机制的意思是数据库中的每个事务在查询数据时,看到的是数据的快照(一个历史版本),而不是数据的当前状态。在多版本并发控制机制中,读操作不用等待写操作,写操作不用等待读操作,只有在两个事务试图同时更新同一个数据行时,才会有等待出现。多版本并发控制机制可以减少数据库中的锁争用,减少用户的等待时间,提高数据库的性能。



    PostgreSQL同时也提供了接口让应用程序显式对数据进行加锁操作。这些接口支持表级锁和行级锁。此外,还提供了建议锁(advisory lock)这样的锁机制,使得应用程序能够完全自主地控制得到和释放锁的时间。



9.2事务的隔离级别
    SQL标准定义了四个事务隔离级别,表9-1列出了所有的隔离级别,事务在不同的隔离级别可以中看到的数据是不相同的。



表9-1. SQL 事务隔离级别

隔离级别
脏读(dirty read)
不可重复读(nonrepeatable read)
影子读(Phantom Read)

Read uncommitted
可能
可能
可能

Read committed
不可能
可能
可能

Repeatable read
不可能
不可能
可能

Serializable
不可能
不可能
不可能




脏读(dirty read)

一个事务可以读取其它还未提交的事务修改的数据。



不可重复读(nonrepeatable read)

一个事务重新读取以前读过的数据时,发现该数据被修改过。



影子读(phantom read)

一个事务两次执行同一个查询,发现第二次查询得到的数据行比第一次查询得到的数据行多。



    PostgreSQL只提供了两种事务隔离级别,分别是Read Committed 和Serializable。使用命令SET TRANSACTION来设置事务的隔离级别。应用程序可以将事务的隔离级别设为Read Uncommitted,但系统会自动将隔离级别设为Read Committed。应用程序也可以将事务的隔离级别设为Repeatable Read,但系统会自动将隔离级别设为Serializable。这样的规则是符合SQL标准的。



9.2.1 Read Committed隔离级别
    Read Committed是PostgreSQL的默认隔离级别。如果一个事务运行在这个隔离级别,事务发出的SELECT命令只能看见在SELECT命令开始执行以前提交的数据。同一个事务的两个先后执行的 SELECT命令可能会看到不同的数据,因为在其它并发执行的事务可能在第一个SELECT命令执行的过程中被提交。另外,事务发出的SELECT命令可以看到该事务以前发出的更新命令(包括INSERT、DELETE和UPDATE)修改过的数据。



    命令UPDATE、 DELETE、SELECT FOR UPDATE和SELECT FOR SHARE可以看到的数据和SELECT命令是一样的。如果一个事务执行命令UPDATE(DELETE、SELECT FOR UPDATE或SELECT FOR SHARE),该命令发现一个数据行R1满足自己的搜索条件,同时有另外一个事务T2已经锁住了数据行T1(T2可能正在删除或更新R1),那么T1将进入等待状态,直到T2执行结束(回滚或提交),T1才能继续运行,根据T2的执行结果,T1有两种执行方式:



(1)如果T2被回滚,T2对R1做的更新将被取消,T1会使用R1原来的值继续运行命令。

(2)如果T2被提交,那要分两种情况:

   (a)T2删除了数据行R1,那么T1继续运行时,将忽略R1, R1对T1正在执行的命令是不可见的。

   (b)T2修改了数据行R1, 那么T1继续运行时,T1正在执行的命令将看见R1的新的值,同时会重新检查R1的新值是否符合该命令的WHERE子句的搜素条件, 如果符合,将使用R1的新值作为搜索结果,如果不符合,将忽略R1的新值。



    Read Committed隔离级别值保证一个事务的单个命令看到的数据是一致的,不能保证一个事务发出的所有命令看到的数据都是一致的。



    Read Committed隔离级别可以满足大部分应用程序的需要,它使用简单,比serializable隔离级别要快速。但那些使用复杂的查询和更新操作的应用可能需要数据库提供更加严格数据的一致性,这种情况下应该使用Serializable隔离级别。



9.2.2 Serializable隔离级别
    Serializable是最严格的隔离级别。在这种隔离级别下,所有并发执行的事务的执行结果和单个事务一个一个地执行的结果是一样的。在这种隔离级别下运行的应用程序的逻辑要复杂一些,在事务不符合可串行化要求的而被终止的情况下,应用程序应该能够重新创建被终止的事务并再次请求数据库执行该事务。



    在Serializable隔离级别下运行的应用程序,一个事务发出的SELECT命令只能看见事务开始运行以前已经提交的数据,看不见在事务开始运行以前没有提交的数据和在事务执行过程中其它并发执行的事务提交的数据。同一个事务的两个先后执行的 SELECT命令看到的数据是一样的。但事务的SELECT命令可以看到该事务以前发出的更新命令(包括INSERT、DELETE和UPDATE)修改过的数据。



    命令UPDATE、 DELETE、SELECT FOR UPDATE和SELECT FOR SHARE可以看到的数据和SELECT命令是一样的。这些命令只能看到事务开始运行以前已经提交的数据。但是如果一个事务执行命令UPDATE(DELETE、SELECT FOR UPDATE或SELECT FOR SHARE),该命令发现一个数据行R1满足自己的搜索条件,同时有另外一个事务T2已经锁住了数据行T1(T2可能正在删除或更新R1),那么T1将进入等待状态,直到T2执行结束(回滚或提交),T1才能继续运行,根据T2的执行结果,T1有两种执行方式:



(1)如果T2被回滚,T2对R1做的更新将被取消,T1会使用R1原来的值继续运行命令。

(2)如果T2被提交,而且T2删除或者更新了R1,T1将被回滚,数据库会发出下面的提示信息:



错误:  当前事务运行在可串行化模式下,与其它并发执行的事务冲突,将被回滚。



    如果应用程序收到上面的错误信息,应该终止执行当前事务,并重新从头开始执行这个事务。注意,只有含有更新操作的事务可能遇到上面的错误而被终止,只读事务永远都不会被被终止。



    Serializable隔离级别保证每个事务在执行过程中看到完全一致的数据。但应用程序的逻辑会变得很复杂,多个事务若同时更新同一个数据行,其中有一个事务就可能失败,应用程序必须重新执行失败的事务,对数据库的压力就会变大。如果事务的更新逻辑非常复杂,导致在Read Committed隔离级别下可能出现不正确的结果,应该使用Serializable隔离级别。通常如果一个事务的几个连续执行的命令需要看到一样的数据,就应该使用Serializable隔离级别。
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏 分享淘帖 顶 踩
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|申请友链|小黑屋|Archiver|手机版|MySQL社区 ( 京ICP备07012489号   
联系人:周生; 联系电话:13911732319

GMT+8, 2024-5-4 14:11 , Processed in 0.065284 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表