比方說,我有一個交易表和transaction_summary表。我創建了以下觸發器以更新transaction_summary表。鎖定在Postgres功能
CREATE OR REPLACE FUNCTION doSomeThing() RETURNS TRIGGER AS
$BODY$
DECLARE
rec_cnt bigint;
BEGIN
-- lock rows which have to be updated
SELECT count(1) from (SELECT 1 FROM transaction_summary WHERE receiver = new.receiver FOR UPDATE) r INTO rec_cnt ;
IF rec_cnt = 0
THEN
-- if there are no rows then create new entry in summary table
-- lock whole table
LOCK TABLE "transaction_summary" IN ACCESS EXCLUSIVE MODE;
INSERT INTO transaction_summary(...) VALUES (...);
ELSE
UPDATE transaction_summary SET ... WHERE receiver = new.receiver;
END IF;
SELECT count(1) from (SELECT 1 FROM transaction_summary WHERE sender = new.sender FOR UPDATE) r INTO rec_cnt ;
IF rec_cnt = 0
THEN
LOCK TABLE "transaction_summary" IN ACCESS EXCLUSIVE MODE;
INSERT INTO transaction_summary(...) VALUES (...);
ELSE
UPDATE transaction_summary SET ... WHERE sender = new.sender;
END IF;
RETURN new;
END;
$BODY$
language plpgsql;
問題:會有死鎖?根據我的理解,可能會發生這樣的情況:
_________
|__table__| <- executor #1 waits on executor #2 to be able to lock the whole table AND
|_________| executor #2 waits on executor #1 to be able to lock the whole table
|_________|
|_________| <- row is locked by executor #1
|_________|
|_________| <- row is locked by executor #2
看來只有選項是每次在交易開始時鎖定整個表。
有你嘗試將'transaction_summary'連接到您的鎖定查詢中,並應用'FOR UPDATE的transaction_summary'? (如果你在'transaction_summary'中有明確定義的主鍵,你可以保留整個表的鎖定值) - 另外,也可以使用'FOUND'特殊變量來代替'rec_cnt'變量。 – pozs 2014-10-20 08:24:30
另外,你想用它達到什麼目的?也許一個多線程安全UPSERT? http://stackoverflow.com/questions/17267417/how-do-i-do-an-upsert-merge-insert-on-duplicate-update-in-postgresql – pozs 2014-10-20 08:29:07
@Pozs - 是的,我想要得到的是一個線程安全_upsert_操作。一個插入_transaction table_可以在_transaction_summary_表上導致兩個_upserts_。 PS:謝謝,我沒有意識到有一個特殊的變量「FOUND」 – robert 2014-10-20 08:47:29