【发布时间】:2011-11-13 23:12:59
【问题描述】:
数据库包含一个用户表。只要用户的用户名是发送到数据库的数据的一部分(即:通过函数),就会将用户添加到表中,并且用户名在表中应该是唯一的。单个用户名也可能在任何给定的函数调用中出现多次。
对于每个用户名,我想获取其现有 ID 或将其插入用户表并返回 ID。
我想出的解决方案是一个 STABLE 函数,它首先尝试从用户表中进行选择,如果失败,它会调用一个尝试插入用户表的 VOLATILE 辅助函数。我更喜欢 STABLE,因为该函数的结果对于事务的其余部分将是相同的,所以我希望它在用户名被多次包含的情况下优化掉,或者它被传递给其他同样的函数寻找它的 ID。
我的问题是:我的初始函数中的 STABLE 是否意味着初始函数永远不会看到并发插入(导致辅助函数中的异常),从而导致无限循环?
我已包含以下定义。
CREATE SCHEMA orgnztn;
CREATE TABLE orgnztn.tUsers (
id serial NOT NULL,
usrid text NOT NULL,
PRIMARY KEY (id),
UNIQUE (usrid)
);
CREATE OR REPLACE FUNCTION orgnztn.getUserID (
IN p_usrid text
)
RETURNS integer
LANGUAGE plpgsql
STABLE
CALLED ON NULL INPUT
SECURITY INVOKER
AS $$
DECLARE
p_id integer;
BEGIN
IF p_usrid IS NULL THEN
RETURN NULL;
END IF;
p_usrid = upper(p_usrid);
LOOP
SELECT id INTO p_id
FROM orgnztn.tUsers
WHERE usrid = p_usrid
FETCH FIRST 1 ROWS ONLY;
IF found THEN
RETURN p_id;
END IF;
BEGIN
RETURN orgnztn.getUserID_helper(p_usrid);
EXCEPTION WHEN unique_violation THEN
-- loop
END;
END LOOP;
END;
$$;
CREATE OR REPLACE FUNCTION orgnztn.getUserID_helper (
IN p_usrid text
)
RETURNS integer
LANGUAGE plpgsql
VOLATILE
CALLED ON NULL INPUT
SECURITY INVOKER
AS $$
DECLARE
p_id integer;
BEGIN
INSERT INTO orgnztn.tUsers (usrid)
VALUES (p_usrid)
RETURNING id INTO p_id;
RETURN p_id;
END;
$$;
【问题讨论】:
标签: postgresql concurrency plpgsql