在 Postgres 中,如果查询包含在具有可序列化隔离级别的事务中,是否需要使用 FOR UPDATE 锁定表中的行?

问题描述 投票:0回答:2

在 Postgres 中,如果查询包含在具有可序列化隔离级别的事务中,是否需要使用 FOR UPDATE 锁定表中的行?换句话说,可序列化事务是否会自行锁定行直到事务完成?

postgresql postgresql-9.5
2个回答
0
投票

您的短语“交易已完成”可能意味着写成“交易已提交”。

请注意,只有在提交事务时才会强制执行隔离级别并避免异常。默认情况下,自动提交是开启的,这意味着在您执行一个 SQL 命令/事务或一组事务后自动运行 COMMIT 命令。如果这是 OFF,那么您的所有事务都必须在每个事务的末尾使用 COMMIT 进行批处理,以便事务级别按照 Postgres 记录的那样运行。提交基本上在实际运行之前将所有事务按顺序放入系统/Postgres 表中。

还要注意,不同会话/用户并行(同时)运行事务时存在隔离级别。所以这个时候就需要锁了。他们将隔离级别称为可序列化,以便任何会话都根据系统时间戳在实际执行时按实际顺序排列。

数据库锁由 Postgres 根据隔离级别正确处理(理论上如果源代码是 100% 完美的)。 Serializable 是最严格的,因此应该避免(四种类别中的)数千种不同的异常情况,并正确处理锁。但我们都知道软件很少是完美的。

https://www.postgresql.org/docs/current/transaction-iso.html

不测试FOR UPDATE是否会被正确处理太难回答了。看看这篇文章。

http://rhaas.blogspot.com/2011/01/locking-in-postgresql.html

经常导致可序列化问题的场景是未实现主键和外键时。或者当索引为表中的数据部分提交时,因为数据集非常大并且索引仍在构建中。因此,如果处理可序列化,参照完整性是必须的。 过去,我处理过超过 200K 记录的层次结构,并且在层次结构的中间需要锁(软编码而不是硬编码——这意味着父 ID 和子 ID 在同一个表中)。这是在 Postgres 中没有正确处理锁的时候,因为隔离级别取决于 Postgres 设计的结构,而不是现实世界中常用的设计。所以在那种情况下,FOR UPDATE 将无法正确锁定,不是因为 Postgres“幕后”代码错误,而是因为软编码层次表的主/外键关系的含义不符合 Postgres 推荐的做法。

我建议您通读并实施基于 PostgreSQL 文档的最佳实践,尤其是您的数据库备份过程。还要测试从备份恢复的实际数据库,并在完成后测试数据库的参照完整性。这可能是此隔离级别未来问题的罪魁祸首,而不是您的 SQL 代码本身。

所以是的,在这些意外情况下,可序列化隔离“应该”处理行级锁。


-1
投票

Serializable 根据我的理解不会自行锁定行。如果它尝试更新相同的行并且只有一个会成功,它将在第二次 txn 中失败。

Serializable隔离级别提供了最严格的事务 隔离。这个级别模拟所有的串行事务执行 已承诺的交易;就好像交易是在一个之后执行的 另一个,顺序地,而不是同时地。然而,就像 Repeatable Read 级别,必须准备使用该级别的应用程序 由于序列化失败而重试事务.

不确定当少数查询使用可序列化隔离级别和其他读取已提交时会发生什么。

© www.soinside.com 2019 - 2024. All rights reserved.