2014-10-04 68 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