数据库包含一个用户表。只要用户的用户名是发送到数据库的数据的一部分(即:通过函数),用户就会被添加到表中,并且用户名在表中应该是唯一的。在任何给定的函数调用中,单个用户名也可能出现多次。
对于每个用户名,我想获取其现有ID或将其插入users表并返回ID。
我提出的解决方案是STABLE函数,它首先尝试从users表中进行选择,如果失败则调用一个尝试插入用户表的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;
$$;
答案 0 :(得分:1)
volatile或stable标志与并发性无关。这些标志的主要用途是用于查询优化。您必须从事务隔离级别中选择一个并使用适当的解决方案 - 取决于您是否使用REPEATABLE READ或READ COMMITED级别。
实际上函数getUserID应该标记为volatile,因为它调用了另一个volatile函数。如果使用REPEATABLE READ级别,则可能存在无限循环。