【问题标题】:SELECT INTO with SELECT FOR UPDATE in PostgreSQL在 PostgreSQL 中使用 SELECT FOR UPDATE SELECT INTO
【发布时间】:2014-11-29 11:30:37
【问题描述】:

假设我有一个 message 关系,我在其中保存使用此命令创建的消息:

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 实际上会锁定返回的行直到事务结束,因此如果我们有 2 个并发事务,则只有一个会真正返回并删除消息。

是这样吗?还是我也应该做SELECT id INTO message_id FROM message WHERE foo1 = p_foo1 LIMIT 1 FOR UPDATE?我找不到任何有关将SELECT INTOFOR UPDATE 结合使用的信息。有什么想法吗?

【问题讨论】:

    标签: sql postgresql transactions plpgsql isolation-level


    【解决方案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 语句的结果返回所有已删除的行。

    【讨论】:

    • READ_COMMITTED 隔离级别是否可以保证没有 2 个并发事务返回相同的消息?更多:实际上我试图保持我的问题示例简单,所以我有SELECT ... ORDER BY,而且似乎不可能对DELETE 做同样的事情。最后,您的回答并没有真正回答我的问题:S,尽管我非常感谢您花时间回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-28
    • 1970-01-01
    • 2017-02-01
    • 2012-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多