我试图理解事务在Postgres中是如何工作的,以及当多个命令试图在同一个表上工作时会发生什么,我的怀疑与我进行的一个小实验有关。
考虑一个名为experiment
的表,该表上有一个触发器(experiment_log
),该触发器在每次更新、删除或插入之后触发。
现在考虑这个函数。
CREATE OR REPLACE FUNCTION test_func() RETURNS void AS $body$
DECLARE
_q_txt text;
version_var integer;
BEGIN
EXECUTE 'DROP TRIGGER IF EXISTS experiment_log ON experiment';
SELECT version INTO version_var FROM experiment;
RAISE NOTICE 'VERSION AFTER DROPPING TRIGGER: %', version_var;
EXECUTE 'SELECT pg_sleep(20);';
SELECT version INTO version_var FROM experiment;
RAISE NOTICE 'VERSION BEFORE RECREATING TRIGGER: %', version_var;
EXECUTE 'CREATE TRIGGER experiment_log AFTER INSERT OR UPDATE OR DELETE ON experiment FOR EACH ROW EXECUTE PROCEDURE experiment_log_trigger_func();';
END;
$body$
language 'plpgsql';
因此,这个函数丢弃触发器,并在重新创建这个触发器之前等待20秒。现在,在函数休眠期间执行的任何更新操作都会阻塞。这意味着,在函数test_func
执行完毕之前,我无法更新experiment
表。
有人能解释这种行为吗?似乎我错过了一些东西来解释这种行为。
1条答案
按热度按时间cbeh67ev1#
这是因为
DROP TRIGGER
在表上放置了一个ACCESS EXCLUSIVE
锁,并且该锁一直保持到事务结束,也就是说,在函数调用的整个持续时间内。如果要临时禁用触发器,请使用
我想从文档中给予你一个参考,但是
DROP TRIGGER
的锁级别没有文档,但是有文档说明SQL语句获取锁:此外,大多数PostgreSQL命令会自动获取适当模式的锁,以确保在执行命令时不会以不兼容的方式删除或修改引用的表。
在那里你还可以找到锁被持有的时间:
一旦获得锁,锁通常会一直保持到事务结束。
要查找
DROP TRIGGER
占用的锁,请尝试以下简单实验:您可以看到表上有一个
ACCESS SHARE
锁和一个ACCESS EXCLUSIVE
锁。