2011-09-09 29 views
0

數據庫包含一個用戶表。只要用戶名是發送到數據庫的數據的一部分(即:通過函數),用戶就會被添加到表中,並且表中的用戶名應該是唯一的。在任何給定的函數調用中,單個用戶名也可能出現多次。穩定函數調用volatile函數:併發性問題

對於每個用戶名,我想獲得其現有ID或插入到用戶表中並返回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

揮發或穩定的標誌不相關的併發性。這些標誌的主要用途是用於查詢優化。您必須從事務隔離級別中選擇一個,並使用適當的解決方案 - 取決於是否使用REPEATABLE READ或READ COMMITED級別。

其實函數getUserID應該被標記爲volatile,因爲它調用了其他的volatile函數。如果您使用REPEATABLE READ級別,則可能存在無限循環。