【问题标题】:Stable function calling volatile function: Concurrency concern稳定函数调用 volatile 函数:并发问题
【发布时间】: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


    【解决方案1】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-26
      • 1970-01-01
      • 2015-11-17
      • 2018-05-24
      • 2011-10-25
      • 2012-06-29
      相关资源
      最近更新 更多