我在 Postgres 中创建了一个过程,该过程将创建一个包含另外三个表(带有 JOINS 的 SELECT)内容的表。然后生成的表将被更改,添加之前不存在的两列,最后在同一过程中我创建了 3 个触发器,这些触发器将应用于这三个表,因此每当在其中任何一个表上发生新的写入时,都会记录相同的实体在新表中
我知道该过程本身是原子的,并且在其自身范围内是事务性的,但该过程无法了解有关这三个表的任何信息。恐怕在创建新表和创建触发器之间的时间里,可能会发生对现有表的一些写入,从而使新表不同步,而新表不会注册这些写入。那不可能发生。
我的表创建/触发器创建过程如下所示:
CREATE OR REPLACE PROCEDURE myschema.table_creation()
LANGUAGE plpgsql
AS $procedure$
begin
create table newtable as
SELECT * FROM myschema.session a NATURAL JOIN (SELECT * FROM myschema.message b NATURAL left JOIN myschema.data) as d;
ALTER TABLE myschema.newtable ADD created_at timestamp;
ALTER TABLE myschema.newtable ADD source text;
CREATE TRIGGER mytrigger
after INSERT
ON myschema.session
FOR EACH ROW
EXECUTE PROCEDURE myschema.trigger_proc();
CREATE TRIGGER mytrigger
after INSERT
ON myschema.messages
FOR EACH ROW
EXECUTE PROCEDURE myschema.trigger_proc();
CREATE TRIGGER mytrigger
after INSERT
ON myschema.data
FOR EACH ROW
EXECUTE PROCEDURE myschema.trigger_proc();
end;
$procedure$
;
如何锁定现有表中的写入以推迟它们,直到整个 table_creation 过程完成?否则,我会遇到竞争条件,并且一些实体将在新表中丢失。我认为我的程序在当前状态下没有任何针对写入的保护
为了绝对确定,请在三个源表上获取排他锁。我建议使用
SHARE
锁。 说明书:
[...] 此模式可保护表免受并发数据更改的影响。
BEGIN;
LOCK TABLE myschema.session, myschema.message, myschema.data IN SHARE MODE; -- !!!
CREATE TABLE newtable AS
SELECT *
FROM myschema.session a
NATURAL JOIN (
SELECT *
FROM myschema.message b
NATURAL LEFT JOIN myschema.data
) d;
ALTER TABLE myschema.newtable -- single command (faster)
ADD created_at timestamp
, ADD source text;
CREATE TRIGGER mytrigger
AFTER INSERT ON myschema.session
FOR EACH ROW EXECUTE FUNCTION myschema.trigger_proc(); -- it's really a function
CREATE TRIGGER mytrigger
AFTER INSERT ON myschema.messages
FOR EACH ROW EXECUTE FUNCTION myschema.trigger_proc();
CREATE TRIGGER mytrigger
AFTER INSERT ON myschema.data
FOR EACH ROW EXECUTE FUNCTION myschema.trigger_proc();
COMMIT;
由于这显然是一次性操作,没有特定于 PL/pgSQL 的操作,因此我不会创建过程。一个简单的交易就可以完成这项工作。