我有这张桌子
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;
我不知道为什么,但不知何故,我有时会在运行该功能时收到此错误
唯一违规:7错误:重复键值违反唯一约束“pk_UserCouponSentMail”语境:SQL语句“INSERT INTO”UserCouponSentMail“VALUES($ 1,$ 2,$ 3,$ 4)”PL / pgSQL函数“UserCouponSentMailInsertOrUpdate”第9行SQL声明
有关这怎么可能发生的任何想法?
两个脚本在同一时间运行此功能的可能性几乎是不可能的。
我在x86_64-redhat-linux-gnu上使用PostgreSQL 8.4.11,由GCC gcc(GCC)4.4.6 20110731(Red Hat 4.4.6-3)编译,64位。
感谢。
答案 0 :(得分: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;
此外,您可能希望在异常块中添加一些关于上下文和事件时间的日志,以期了解并发执行的原因。