触发器有时会因重复键错误而失败
Trigger sometimes fails with duplicate key error
我在 AWS 中使用 PostgreSQL RDS 实例。基本上,有一个查询将数据插入第一个 table,我们称它为 table
。那里的数据在某些字段中可以有重复项(显然主键除外)。
然后是更新另一个 table、infotable
的触发器,不允许重复。
触发器:
CREATE TRIGGER insert_infotable AFTER INSERT ON table
FOR EACH ROW EXECUTE PROCEDURE insert_infotable();
触发函数的相关部分如下所示:
CREATE OR REPLACE FUNCTION insert_infotable() RETURNS trigger AS $insert_infotable$
BEGIN
--some irrelevant code
IF NOT EXISTS (SELECT * FROM infotable WHERE col1 = NEW.col1 AND col2 = NEW.col2) THEN
INSERT INTO infotable(col1, col2, col3, col4, col5, col6) values (--some values--);
END IF;
RETURN NEW;
END;
$insert_infotable$ LANGUAGE plpgsql;
table infotable
对列 col1
和 col2
.
具有 UNIQUE 约束
一般情况下一切正常,但很少,大约每 1k 次插入一次,触发器 returns table infotable
的错误 'duplicate key value violates unique constraint "unique_col1_and_col2"'。这不应该发生,因为触发函数中有 IF NOT EXISTS
部分。
第一个问题是这可能是什么原因造成的?我唯一能想到的是两个用户同时获取相同信息的比赛,都触发了触发器,但随后一个用户通过触发器更新了第二个 table,第二个用户得到了重复的错误。因此,他的整个插入查询都失败了,包括插入主 table
.
如果是这样,我该怎么办?对于本应有 100 多个用户同时插入数据的 table,在插入时使用锁定是否是个好主意?
如果是,我应该使用什么类型的锁,我应该锁什么 table -- 主 table 或第二个, 哪个被触发器修改了? (或者我想我应该用我的主插入语句或在触发器函数中锁定吗?)
是的,这是一个竞争条件。两个这样的触发器 运行 不会同时看到彼此的修改,因为事务尚未提交。
由于您对 infotable
有唯一约束,您可以简单地使用
INSERT INTO infotable ...
ON CONFLICT (col1, col2) DO NOTHING;
我在 AWS 中使用 PostgreSQL RDS 实例。基本上,有一个查询将数据插入第一个 table,我们称它为 table
。那里的数据在某些字段中可以有重复项(显然主键除外)。
然后是更新另一个 table、infotable
的触发器,不允许重复。
触发器:
CREATE TRIGGER insert_infotable AFTER INSERT ON table
FOR EACH ROW EXECUTE PROCEDURE insert_infotable();
触发函数的相关部分如下所示:
CREATE OR REPLACE FUNCTION insert_infotable() RETURNS trigger AS $insert_infotable$
BEGIN
--some irrelevant code
IF NOT EXISTS (SELECT * FROM infotable WHERE col1 = NEW.col1 AND col2 = NEW.col2) THEN
INSERT INTO infotable(col1, col2, col3, col4, col5, col6) values (--some values--);
END IF;
RETURN NEW;
END;
$insert_infotable$ LANGUAGE plpgsql;
table infotable
对列 col1
和 col2
.
一般情况下一切正常,但很少,大约每 1k 次插入一次,触发器 returns table infotable
的错误 'duplicate key value violates unique constraint "unique_col1_and_col2"'。这不应该发生,因为触发函数中有 IF NOT EXISTS
部分。
第一个问题是这可能是什么原因造成的?我唯一能想到的是两个用户同时获取相同信息的比赛,都触发了触发器,但随后一个用户通过触发器更新了第二个 table,第二个用户得到了重复的错误。因此,他的整个插入查询都失败了,包括插入主 table
.
如果是这样,我该怎么办?对于本应有 100 多个用户同时插入数据的 table,在插入时使用锁定是否是个好主意?
如果是,我应该使用什么类型的锁,我应该锁什么 table -- 主 table 或第二个, 哪个被触发器修改了? (或者我想我应该用我的主插入语句或在触发器函数中锁定吗?)
是的,这是一个竞争条件。两个这样的触发器 运行 不会同时看到彼此的修改,因为事务尚未提交。
由于您对 infotable
有唯一约束,您可以简单地使用
INSERT INTO infotable ...
ON CONFLICT (col1, col2) DO NOTHING;