遇到序列化失败的条件是什么?

时间:2011-10-09 17:39:01

标签: sql postgresql transactions transaction-isolation

Serializable Isolation Level上的

The PostgreSQL manual page声明:

  

[Like]可重复读取级别,由于序列化失败,必须准备使用此级别的应用程序重试事务。

在可重复读取或可序列化级别遇到序列化失败的条件是什么?

我试图在运行psql的两个实例的情况下导致序列化失败,但即使事务是由一个实例提交的,另一个实例在可序列化级别的事务中,而另一个实例也是成功的承诺改变。两者都只是将记录插入表中,所以我可能需要尝试更复杂的东西。

基本上我试图了解序列化失败时会发生什么以及序列化失败的原因。

3 个答案:

答案 0 :(得分:6)

序列化失败有很多可能的原因。从技术上讲,两个事务之间的死锁是序列化失败的一种形式,如果对模式(数据库结构)进行并发修改,则可能发生在任何隔离级别。既然你在询问PostgreSQL,你应该知道在PostgreSQL中,这种类型的序列化失败会从其他类型获得单独的SQLSTATE:'40P01'。所有其他序列化失败返回'40001'。这个答案的其余部分将集中在PostgreSQL中的这些非死锁变种。

在活动副本(“热备用”)之外,这些只能在两个更严格的隔离级别发生:REPEATABLE READ和SERIALIZABLE。在REPEATABLE READ级别,这些只能由于写入冲突而发生 - 两个并发事务尝试更新或删除相同(现有)行。进行尝试的第一个事务锁定行并继续。如果提交,则第二个事务因序列化失败而失败。如果第一个事务因任何原因回滚,则被阻止的事务将被释放以继续,并将在该行上获取自己的锁。此行为与事务持续时间内的单个“快照”结合使用,也称为“快照隔离”。

在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或Wiki页面上的PostgreSQL文档页面,其中提供了在http://wiki.postgresql.org/wiki/SSI

的新的更严格的隔离级别中如何发生序列化失败的示例

如果您正在使用Hot Standby功能,如果存在长时间运行的查询,则可能会在只读副本上发生序列化故障,维护稳定的数据视图需要数据库阻止复制长。有一些配置设置可以让您平衡复制数据的“新鲜度”与长时间运行查询的容差。某些用户可能希望创建多个副本,以便他们可以拥有最新数据(甚至可能选择同步复制),同时允许另一个副本根据需要延迟为长时间运行的查询提供服务。

编辑以提供另一个链接:在第38届超大型数据库国际会议上发表的题为Serializable Snapshot Isolation in PostgreSQL的论文提供了比其他链接更多的细节和观点,以及为此奠定基础的论文的参考文献实施

答案 1 :(得分:5)

对于REPEATABLE READ,此示例将执行:

准备阶段:

psql-0> CREATE TABLE foo(key int primary key, val int);
CREATE TABLE
psql-0> INSERT INTO foo VALUES(1, 42);

现在请关注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

SERIALIZABLE的示例在PostgreSQL 9.1的文档中,从这里开始应该没问题。

答案 2 :(得分:4)

如果这有助于任何人,这里是Freenode上#postgresql的成绩单:

  

[14:36]< dtrebbien>   What are the conditions for encountering a serialization failure?

     

[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> “任何可并行序列化的集合   交易将具有与在a处运行交易相同的效果   时间“

     

[14:44]< dtrebbien> PostgreSQL有哪些规则   引擎跟着?

     

[14:44]< dtrebbien>即如果更改了一行,是否会触发   失败了?

     

[14:44]< johto> 9.1中的可序列化隔离模式确实如此   复杂的

     

[14:45]< dtrebbien>我想。

     

[14:45]< dtrebbien>我也读到了Serializable级别   以某种方式“修复”

     

[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吗?   溢出?

     

[15:07]< selenamarie> dtrebbien:当然:))

     

[15:07]< dtrebbien>我不知道它是否会对任何人有所帮助。它   威力。

     

[15:08]< selenamarie> dtrebbien:我发布了凯文的笔记   Grittner在这里谈到这个问题:   http://www.chesnok.com/daily/2011/03/24/raw-notes-from-kevin-grittners-talk-on-ssi/