Postgresql
如何在不通過連接返回數據的情況下鎖定 FOR UPDATE 行?
我想做這樣的事情:
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
在這兩個語句中使用。