调用volatile函数的稳定函数:并发关注

时间:2011-09-09 17:00:09

标签: postgresql concurrency plpgsql

数据库包含一个用户表。只要用户的用户名是发送到数据库的数据的一部分(即:通过函数),用户就会被添加到表中,并且用户名在表中应该是唯一的。在任何给定的函数调用中,单个用户名也可能出现多次。

对于每个用户名,我想获取其现有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;
    $$;

1 个答案:

答案 0 :(得分:1)

volatile或stable标志与并发性无关。这些标志的主要用途是用于查询优化。您必须从事务隔离级别中选择一个并使用适当的解决方案 - 取决于您是否使用REPEATABLE READ或READ COMMITED级别。

实际上函数getUserID应该标记为volatile,因为它调用了另一个volatile函数。如果使用REPEATABLE READ级别,则可能存在无限循环。