假设我有一个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实际上会锁定返回的行,直到事务结束,所以如果我们有两个并发事务,那么实际上只有一个事务会返回并删除消息。
真的是这样吗?或者我也应该做SELECT id INTO message_id FROM message WHERE foo1 = p_foo1 LIMIT 1 FOR UPDATE?我找不到任何关于结合使用SELECT INTO和FOR UPDATE的信息。对此有什么想法吗?
发布于 2014-10-05 02:08:45
您可以在单个语句中做到这一点,不需要select:
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语句的结果。
https://stackoverflow.com/questions/26195339
复制相似问题