Postgresql

如何在不通過連接返回數據的情況下鎖定 FOR UPDATE 行?

  • January 14, 2020

我想做這樣的事情:

begin;
select * from foos where owner_id=123 and unread=true order by id for update;
update foos set unread=false where owner_id=123 and unread=true;
commit;

目標是在兩個程序同時執行 UPDATE 時避免死鎖。此處描述了更多問題:為什麼我會遇到單個 UPDATE 查詢的死鎖?

在我獲取鎖的語句中,我不需要有關行的任何資訊。我只想鎖定那些特定的行。有沒有辦法做到這一點(優雅或hacky),它告訴postgres不要做任何實際給我數據的工作?

關於避免死鎖的目標:請參閱我對您的相關問題的回答:

關於標題中的問題:

SELECT您可以使用帶有鎖定子句的空列表:

SELECT FROM foos WHERE owner_id = 123 AND unread ORDER BY id FOR UPDATE;

仍然鎖定所有選定的行,但不返回任何數據。但是,仍然返回空行,因此您仍然可以像往常一樣獲得行數。

或者,受a_horse 評論的啟發:

SELECT count(*) AS locked_rows
FROM  (SELECT FROM foos WHERE owner_id = 123 AND unread ORDER BY id FOR UPDATE) sub;

這樣,您將獲得具有鎖定行數的單個結果行。0(如果有行,您可以中止。)行都被鎖定。子查詢中的SELECT列表仍然可以是空的(最短、最便宜)。

旁白:and unread=true只是一種嘈雜、效率較低的說法AND unread

如果unlocked可以NULL,請考慮unread IS NOT true在這兩個語句中使用。

引用自:https://dba.stackexchange.com/questions/257188