2013-05-20 33 views
0

我有這個表爲什麼以前驗證時查詢會返回PK衝突?

CREATE TABLE "UserCouponSentMail" 
(
    "IdUser" integer NOT NULL, 
    "IdCoupon" integer NOT NULL, 
    "SendType" character varying(100), 
    "Date" timestamp without time zone NOT NULL DEFAULT ('now'::text)::timestamp without time zone, 
    CONSTRAINT "pk_UserCouponSentMail" PRIMARY KEY ("IdUser" , "IdCoupon"), 
    CONSTRAINT "pk_UserCouponSentMail_GroceryCoupon" FOREIGN KEY ("IdCoupon") 
     REFERENCES "GroceryCoupon" ("IdGroceryCoupon") MATCH SIMPLE 
     ON UPDATE NO ACTION ON DELETE NO ACTION 
) 
WITH (OIDS=FALSE); 

這個功能

CREATE OR REPLACE FUNCTION "UserCouponSentMailInsertOrUpdate"(integer, integer, character varying, timestamp without time zone) 
    RETURNS void AS 
$BODY$ 
BEGIN 
    IF (EXISTS(SELECT * FROM "UserCouponSentMail" WHERE "IdUser" = $1 AND "IdCoupon" = $2)) THEN 
     UPDATE "UserCouponSentMail" SET 
      "SendType" = $3, 
      "Date" = $4 
     WHERE 
      "IdUser" = $1 AND "IdCoupon" = $2; 
    ELSE 
     INSERT INTO "UserCouponSentMail" VALUES ($1, $2, $3, $4); 
    END IF; 
    RETURN; 
END 
$BODY$ 
    LANGUAGE plpgsql VOLATILE 
    COST 100; 

而且我不知道爲什麼,但不知何故,我同時運行的功能

Unique violation: 7 ERROR: duplicate key value violates unique constraint "pk_UserCouponSentMail" CONTEXT: SQL statement "INSERT INTO "UserCouponSentMail" VALUES ($1 , $2 , $3 , $4)" PL/pgSQL function "UserCouponSentMailInsertOrUpdate" line 9 at SQL statement

任何有時會收到此錯誤想法如何發生?

兩個腳本幾乎不可能在同一時間以相同的參數運行這個函數。

我在x86_64-redhat-linux-gnu上使用PostgreSQL 8.4.11,由GCC gcc(GCC)4.4.6 20110731(Red Hat 4.4.6-3)編譯,64位。

謝謝。

回答

1

對於(IdUser,IdCoupon)具有相同值的併發執行似乎是唯一合理的解釋。

這個問題說這幾乎是不可能的,但多次執行並不總是有前瞻性。例如,在Web應用程序的上下文中,可能會出現具有完全相同數據的表單的雙重帖子。

爲了避免在PLPGSQL級別的錯誤,你可以使用異常塊:

BEGIN 
    IF (EXISTS...) THEN 
    UPDATE the unique corresponding row 
    ELSE 
    INSERT new row 
    END IF; 
EXCEPTION WHEN unique_violation THEN 
    UPDATE the unique row 
END; 

你也可能要添加一些日誌中有關上下文異常塊和事件在時間希望理解爲什麼會發生併發執行。