我有一张名为deposits
存款时,表格被锁定,因此查询类似于:
SELECT * FROM deposits WHERE id=123 FOR UPDATE
我假设FOR UPDATE
正在锁定表,以便我们可以在没有其他线程踩踏数据的情况下操纵它。
但是,当其他存款试图锁定桌子时,会出现问题。发生的事情是,在锁定表格和调用psql_commit()
之间的某个地方失败并保持锁定愚蠢的长时间。我需要帮助解决一些问题:
尝试获取锁定的后续查询应该失败,我尝试使用NOWAIT
实现此目的但更喜欢超时方法(因为可以等待,只是不等待&#39 ;愚蠢的时间')
理想情况下,我会在传递中关闭此功能,让我的初始查询仅保持锁定一段时间,这是否可以使用postgresql?
我是否可以使用其他一些神奇功能来查询(类似于NOWAIT),它只会在失败前等待锁定4秒?
由于代码库令人痛苦的整体意大利面代码性质,它不仅仅是改变全局配置的问题,它还需要是基于每个查询的解决方案
感谢你的帮助,我会继续四处寻找,但我没有多少运气。这是psql的一个不存在的函数,因为我发现了这个:http://www.postgresql.org/message-id/40286F1F.8050703@optusnet.com.au
答案 0 :(得分:46)
我假设FOR UPDATE正在锁定表,以便我们可以在没有其他线程踩踏数据的情况下操纵它。
不。 FOR UPDATE
仅锁定这些行,以便另一个尝试锁定它们的事务(使用FOR SHARE
,FOR UPDATE
,UPDATE
或{{1} })阻塞,直到您的事务提交或回滚。
如果您想要一个阻止插入/更新/删除的整个表锁,您可能需要DELETE
。
尝试获取锁定的后续查询应该会失败,我尝试使用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';
交易后。
理想情况下,我会在传递中关闭它,并让我的初始查询仅持有锁定一段时间,这是否可以使用postgresql?
有一个语句超时,但锁定保存在事务级别。没有交易超时功能。
如果您正在运行单语句事务,则可以在运行语句之前设置BEGIN
以限制其运行时间。但这并不是限制它可以保持锁定的时间,因为它可能会等待900ms的允许1s来锁定,只实际保持锁定100ms,然后被超时取消。
我是否可以使用其他一些神奇的功能来查询(类似于NOWAIT),它只会在失败前等待锁定4秒?
没有。你必须:
statement_timeout
由于代码库令人痛苦的整体意大利面代码性质,它不仅仅是改变全局配置的问题,它有点需要是基于每个查询的解决方案
BEGIN;
SET LOCAL lock_timeout = '4s';
SELECT ....;
COMMIT;
是合适的,也是首选。
在查询文本中无法执行此操作,它必须是单独的语句。
您链接到的邮件列表帖子是一个从未实现的虚构语法提案(至少在公共PostgreSQL版本中)并且不存在。
在这种情况下,您可能需要考虑"乐观并发控制",通常称为"乐观锁定"。它以更高的查询重复率和更多应用程序逻辑的需要为代价,让您更好地控制锁定行为。