Dan*_*ien 13 sql postgresql transactions transaction-isolation
Serializable Isolation Level上的PostgreSQL手册页指出:
[Like]可重复读取级别,使用此级别的应用程序必须准备好因序列化失败而重试事务.
在可重复读取或可序列化级别遇到序列化失败的条件是什么?
我尝试使用两个psql运行实例来引发序列化失败,但即使事务是由一个实例提交的,另一个实例在可序列化级别的事务中,而另一个实例在提交其更改时成功.两者都只是将记录插入表中,所以也许我需要尝试更复杂的东西.
基本上我试图了解在序列化失败的情况下会发生什么以及如何出现序列化失败.
序列化失败有许多可能的原因.从技术上讲,两个事务之间的死锁是序列化失败的一种形式,如果对模式(数据库结构)进行并发修改,则可能发生在任何隔离级别.既然你在询问PostgreSQL,你应该知道在PostgreSQL中,这种类型的序列化失败会从其他类型获得单独的SQLSTATE:'40P01'.所有其他序列化失败返回'40001'.这个答案的其余部分将集中在PostgreSQL中的这些非死锁变种.
在活动副本("热备用")之外,这些只能发生在两个更严格的隔离级别:REPEATABLE READ和SERIALIZABLE.在REPEATABLE READ级别,这些只能由于写入冲突而发生 - 两个并发事务尝试更新或删除相同(现有)行.进行尝试的第一个事务锁定行并继续.如果提交,则第二个事务因序列化失败而失败.如果第一个事务因任何原因回滚,则被阻止的事务将被释放以继续,并将在该行上获取自己的锁.此行为与事务持续时间内的单个"快照"结合使用,也称为SNAPSHOT ISOLATION.
在PostgreSQL版本9.1之前,SERIALIZABLE事务的工作方式完全相同.从9.1开始PostgreSQL使用一种名为Serializable Snapshot Isolation的新技术来确保任何可序列化事务集的行为与这些事务的某些串行(一次一个)执行完全一致.在9.1中使用SERIALIZABLE事务时,您的应用程序应该为除ROLLBACK之外的任何语句的序列化失败做好准备 - 即使在只读事务中甚至在COMMIT上也是如此.有关更多信息,请参阅http://www.postgresql.org/docs/current/interactive/transaction-iso.html上的PostgreSQL文档页面或Wiki页面,其中提供了在新的,更严格的隔离级别中如何发生序列化失败的示例在http://wiki.postgresql.org/wiki/SSI
如果使用Hot Standby功能,如果存在长时间运行的查询,则可能会在只读副本上发生序列化故障,维护稳定的数据视图需要数据库阻止复制时间过长.有一些配置设置可以让您平衡复制数据的"新鲜度"与长时间运行查询的容差.某些用户可能希望创建多个副本,以便他们可以拥有最新数据(甚至可能选择同步复制),同时允许其他用户根据需要延迟服务长时间运行的查询.
编辑提供另一个链接:在第38届国际超大型数据库会议上发表的题为" PostgreSQL中的可序列化快照隔离 "的论文提供了比其他链接更多的细节和观点,以及为这一实现奠定基础的论文的参考.
对于REPEATABLE READ这个例子就可以了:
准备阶段:
psql-0> CREATE TABLE foo(key int primary key, val int);
CREATE TABLE
psql-0> INSERT INTO foo VALUES(1, 42);
Run Code Online (Sandbox Code Playgroud)
现在请关注psql- X部分,指示操作的交错:
psql-1> BEGIN ISOLATION LEVEL REPEATABLE READ;
psql-1> UPDATE foo SET val=val+1;
UPDATE 1
psql-2> BEGIN ISOLATION LEVEL REPEATABLE READ;
psql-2> UPDATE foo SET val=val+1;
*** no output, transaction blocked ***
psql-1> COMMIT;
psql-2> *** unblocks ***
ERROR: could not serialize access due to concurrent update
Run Code Online (Sandbox Code Playgroud)
一个例子SERIALIZABLE是在PostgreSQL 9.1的文档中,从这里应该没有问题.
如果这对任何人都有帮助,请参考以下Freenode上#postgresql的文字记录:
[14:36] <dtrebbien> 遇到序列化失败的条件是什么?
[14:36] <dtrebbien> ^遇到序列化失败的条件是什么?
[14:37] <dtrebbien>是否有一个PostgreSQL开发人员可以识别序列化失败的条件?
[14:38] <peerce> http://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-SERIALIZABLE
[14:43] <dtrebbien>“任何并发可序列化事务集都具有与每次运行一次相同的效果”
[14:44] <dtrebbien> PostgreSQL引擎遵循哪些规则?
[14:44] <dtrebbien>即如果更改了行,是否会触发失败?
[14:44] <johto> 9.1中的可序列化隔离模式非常复杂
[14:45] <dtrebbien>我想。
[14:45] <dtrebbien>我也读到,可序列化级别以某种方式“固定”
[14:45] <RhodiumToad> dtrebbien:在9.1之前,基本规则是,如果事务试图更改其当前值不可见的行,则失败
[14:46] <dtrebbien> RhodiumToad:很有意思。
[14:46] <dtrebbien>另外,访问值,对吗?
[14:46] <selenamarie> dtrebbien:除了其他人所说的,其背后的基本前提是检测依赖循环
[14:47] <dtrebbien>哦。
[14:50] <dtrebbien>可以公平地说,在9.1中,触发隔离级别的规则变得更加复杂,以便基本上减少“假阳性”序列化异常吗?
[14:51] <johto>使它们变得复杂是因为更简单的Rulex不能捕获所有序列化异常
[14:51] <dtrebbien>啊!我懂了。
[14:51] <dtrebbien>这就是发行说明说“已修复”的原因。
[14:52] <RhodiumToad> dtrebbien:访问不可见的值不是错误,因为它只是获得了快照时可见的值。
[14:53] <RhodiumToad> dtrebbien:只读的可序列化查询只是从快照时间开始就看到数据库的静态状态。
[14:54] <RhodiumToad> dtrebbien:除了带有TRUNCATE的小皱纹之外,所有序列化问题都涉及读/写查询
[15:03] <dtrebbien> RhodiumToad,johto,selenamarie和peerce:您介意我是否将此对话的成绩单发布到Stack Overflow?
[15:07] <selenamarie> dtrebbien:肯定:)
[15:07] <dtrebbien>我不知道它是否会帮助任何人。它可能。
[15:08] <selenamarie> dtrebbien:我在这里发表了凯文·格里特纳(Kevin Grittner)的演讲中的笔记:http : //www.chesnok.com/daily/2011/03/24/raw-notes-from-kevin-grittners-在ssi上说话/