PostgreSQL 锁定行无限期

Posted

技术标签:

【中文标题】PostgreSQL 锁定行无限期【英文标题】:PostgreSQL Lock Row on indefinitely time 【发布时间】:2014-01-05 12:26:29 【问题描述】:

我想由某个用户锁定一行,直到他无限期地使用这一行,并且他必须在完成后解锁它。因此,任何其他用户将无法为自己锁定此行。可以在数据库级别上做吗?

【问题讨论】:

【参考方案1】:

您可以使用长期事务来执行此操作,但这样做会出现性能问题。这听起来更像是乐观并发控制的工作。

可以打开一个事务并执行SELECT 1 FROM mytable WHERE clause to match row FOR UPDATE;。然后保持交易开放,直到你完成。这样做的问题是,它可能会导致真空问题,从而导致表和索引膨胀,其中表被删除的数据填满,而索引则被指向过时块的条目填满。

最好使用advisory lock。您仍然必须保持连接保持锁打开,但它不必保持打开的空闲事务,因此影响要小得多。但是,希望更新行的事务必须显式检查冲突的咨询锁,否则它们可以继续进行,就好像它没有被锁定一样。这种方法对于大量表(由于有限的咨询锁命名空间)或大量并发锁(由于连接数)的扩展性也很差。

如果您不能确保您的客户端应用始终明确获得咨询锁,您可以使用触发器检查咨询锁并等待它。但是,这可能会造成死锁问题。

因此,最好的方法可能是有一个记录用户 ID 的locked_by 字段和一个记录锁定时间的locked_time 字段。在应用程序级别和/或使用触发器执行此操作。要处理获取锁的并发尝试,您可以使用optimistic concurrency control 技术,其中设置locked_bylocked_timeUPDATE 上的WHERE 子句如果其他人先到达那里将不匹配,因此行数将是零,你会知道你失去了锁的比赛,必须重新检查。 WHERE 子句通常测试 locked_bylocked_time。所以你会写这样的东西:

UPDATE t
SET locked_by = 'me' AND locked_time = current_timestamp
WHERE locked_by IS NULL AND locked_time IS NULL
AND id = [ID of row to update];

(这是一种用于获取锁的简化乐观锁定模式,您不介意其他人是否加入并执行了整个事务。如果您想要更严格的排序,则使用行版本列或检查last_modified 列没有改变。)

【讨论】:

看起来像查询更新“locked_by IS NULL AND locked_time IS NULL”的所有行,但是只更新一行怎么样?而且我认为可能是应用程序下降并且行保持锁定的情况,这没关系,但是当用户重新启动程序时,locked_by = 'me' 的行已经存在,所以他需要先接受它。 PS对不起我的英语 @Miles 是的,而是。应该包括感兴趣的 ID。固定。 @Miles 至于应用程序失败,您不能轻易地同时拥有“崩溃时自动解锁”和“无限期锁定”。您可能不得不依赖与 PostgreSQL 的开放 TCP 连接,无论是咨询锁定还是长时间运行的 tx(但如果数据库承受大量写入负载,那么长时间运行的 tx 真的很糟糕)。

以上是关于PostgreSQL 锁定行无限期的主要内容,如果未能解决你的问题,请参考以下文章

Postgres:更新与物化视图连接的表?错误:视图无法在物化视图中锁定行

PostgreSQL - 用户“postgres”的对等身份验证失败

在postgres中触发以锁定带有列表的表

如何在 postgresql 中进行一些未经授权的登录尝试后锁定数据库用户帐户

PostgreSQL时区调整

如何在 postgres 中设置锁定超时 - Hibernate