2014-10-04 73 views
3
UPDATE

假設我有一個message關係,我保存已被該命令創建的消息:SELECT INTO與SELECT在PostgreSQL中

CREATE TABLE message 
(
    id serial primary key, 
    foo1 integer, 
    foo2 integer, 
    foo3 text 
) 

而且我們有得到了消息,並從關係中刪除的功能,像這樣:

CREATE FUNCTION get_and_delete_message(p_foo1 integer) 
RETURNS TABLE(r_id integer, r_foo1 integer, r_foo2 integer, r_foo3 text) AS $$ 
DECLARE 
    message_id integer; 
BEGIN 
    SELECT id INTO message_id FROM message WHERE foo1 = p_foo1 LIMIT 1; 
    RETURN QUERY SELECT * FROM message WHERE foo1 = p_foo1 LIMIT 1; 
    DELETE FROM message where id = message_id; 
END; 
$$ LANGUAGE plpgsql; 

假設READ_COMMITTED隔離級別,它可能是從兩個用戶兩個併發事務返回相同的消息,但顯然僅有的刪除/獲取它。這不是我的應用程序所需的行爲,我希望只有一個用戶閱讀一條消息。

假設REPEATABLE_READ這不會發生。

但閱讀FOR UPDATE後,我想也許它仍然可以使用READ_COMMITTED水平和改變get_and_delete_message功能如下:

... 
    BEGIN 
     SELECT id INTO message_id FROM message WHERE foo1 = p_foo1 LIMIT 1; 
     RETURN QUERY SELECT * FROM message WHERE foo1 = p_foo1 LIMIT 1 FOR UPDATE; 
     DELETE FROM message where id = message_id; 
    END; 
    ... 

從我的理解,在第二SELECT使用FOR UPDATE實際上將鎖定返回的行直到事務結束,所以如果我們有兩個併發事務,則只有一個事實上會返回並刪除該消息。

這是這種情況?或者我也應該做SELECT id INTO message_id FROM message WHERE foo1 = p_foo1 LIMIT 1 FOR UPDATE?我找不到有關SELECT INTOFOR UPDATE相結合的任何信息。有關於此的任何想法?

回答

1

你可以做,在一個單獨的語句,不需要一個選擇:

CREATE FUNCTION get_and_delete_message(p_foo1 integer) 
RETURNS TABLE(r_id integer, r_foo1 integer, r_foo2 integer, r_foo3 text) 
AS $$ 
    DELETE FROM message 
    where foo1 = p_foo1 
    returning *; 
END; 
$$ LANGUAGE sql; 

這將刪除該行,然後返回所有被刪除的行作爲delete語句的結果。

+2

這是在'READ_COMMITTED'隔離級別去保證我沒有2個併發事務返回相同的消息嗎?更多的東西:其實我試圖讓我的問題的例子簡單,所以我有'SELECT ... ORDER BY',似乎不可能用'DELETE'做同樣的事情。 最後,你的回答並沒有真正回答我的問題:S,儘管我很欣賞你回答的時間 – insumity 2014-10-04 23:52:20