控制PostgreSQL锁的持续时间等待

时间:2014-01-07 03:35:03

标签: postgresql locking

我有一张名为deposits

的表格

存款时,表格被锁定,因此查询类似于:

SELECT * FROM deposits WHERE id=123 FOR UPDATE

我假设FOR UPDATE正在锁定表,以便我们可以在没有其他线程踩踏数据的情况下操纵它。

但是,当其他存款试图锁定桌子时,会出现问题。发生的事情是,在锁定表格和调用psql_commit()之间的某个地方失败并保持锁定愚蠢的长时间。我需要帮助解决一些问题:

  1. 尝试获取锁定的后续查询应该失败,我尝试使用NOWAIT实现此目的但更喜欢超时方法(因为可以等待,只是不等待&#39 ;愚蠢的时间')

  2. 理想情况下,我会在传递中关闭此功能,让我的初始查询仅保持锁定一段时间,这是否可以使用postgresql?

  3. 我是否可以使用其他一些神奇功能来查询(类似于NOWAIT),它只会在失败前等待锁定4秒?

  4. 由于代码库令人痛苦的整体意大利面代码性质,它不仅仅是改变全局配置的问题,它还需要是基于每个查询的解决方案

  5. 感谢你的帮助,我会继续四处寻找,但我没有多少运气。这是psql的一个不存在的函数,因为我发现了这个:http://www.postgresql.org/message-id/40286F1F.8050703@optusnet.com.au

1 个答案:

答案 0 :(得分:46)

  

我假设FOR UPDATE正在锁定表,以便我们可以在没有其他线程踩踏数据的情况下操纵它。

不。 FOR UPDATE仅锁定这些行,以便另一个尝试锁定它们的事务(使用FOR SHAREFOR UPDATEUPDATE或{{1} })阻塞,直到您的事务提交或回滚。

如果您想要一个阻止插入/更新/删除的整个表锁,您可能需要DELETE

  1.   

    尝试获取锁定的后续查询应该会失败,我尝试使用NOWAIT实现这一点,但更喜欢使用超时方法(因为可以等待,只是不要等待愚蠢的时间&#39 ;)

    the lock_timeout setting。这是在9.3中添加的,在旧版本中不可用。

    使用LOCK TABLE ... IN EXCLUSIVE MODE可以实现旧版本的粗略近似值,但这可能导致语句被不必要地取消。如果statement_timeout为1并且语句在锁定时等待950毫秒,则它可能会获得锁定并继续,仅在超时时立即取消。不是你想要的。

    设置statement_timeout没有查询级别的方式,但可以,应该只是:

    lock_timeout

    在您SET LOCAL lock_timeout = '1s';交易后

  2.   

    理想情况下,我会在传递中关闭它,并让我的初始查询仅持有锁定一段时间,这是否可以使用postgresql?

    有一个语句超时,但锁定保存在事务级别。没有交易超时功能。

    如果您正在运行单语句事务,则可以在运行语句之前设置BEGIN以限制其运行时间。但这并不是限制它可以保持锁定的时间,因为它可能会等待900ms的允许1s来锁定,只实际保持锁定100ms,然后被超时取消。

  3.   

    我是否可以使用其他一些神奇的功能来查询(类似于NOWAIT),它只会在失败前等待锁定4秒?

    没有。你必须:

    statement_timeout
  4.   

    由于代码库令人痛苦的整体意大利面代码性质,它不仅仅是改变全局配置的问题,它有点需要是基于每个查询的解决方案

    BEGIN; SET LOCAL lock_timeout = '4s'; SELECT ....; COMMIT; 是合适的,也是首选。

    在查询文本中无法执行此操作,它必须是单独的语句。

    您链接到的邮件列表帖子是一个从未实现的虚构语法提案(至少在公共PostgreSQL版本中)并且不存在。

  5. 在这种情况下,您可能需要考虑"乐观并发控制",通常称为"乐观锁定"。它以更高的查询重复率和更多应用程序逻辑的需要为代价,让您更好地控制锁定行为。