我试图了解用于触发功能的锁的类型。
简化功能:
CREATE OR REPLACE FUNCTION max_count() RETURNS TRIGGER AS
$$
DECLARE
max_row INTEGER := 6;
association_count INTEGER := 0;
BEGIN
LOCK TABLE my_table IN ROW EXCLUSIVE MODE;
SELECT INTO association_count COUNT(*) FROM my_table WHERE user_id = NEW.user_id;
IF association_count > max_row THEN
RAISE EXCEPTION 'Too many rows';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE CONSTRAINT TRIGGER my_max_count
AFTER INSERT OR UPDATE ON my_table
DEFERRABLE INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE max_count();
我最初打算使用EXCLUSIVE
,但感觉太重了。我真正想要的是确保在执行此函数期间,不会将与相关的user_id
相关的新行添加到表中。
答案 0 :(得分:1)
如果要防止并发事务修改表,则SHARE
锁是正确的。但是,如果两个这样的事务同时运行,则可能导致死锁-每个事务都修改了一些行,并在尝试升级表锁时被另一个阻塞。
此外,所有与SHARE UPDATE EXCLUSIVE
冲突的表锁都将导致自动真空取消,这将在频繁发生时导致表膨胀。
因此远离表锁,它们通常是错误的事情。
执行此操作的更好方法是根本不使用任何显式锁定,而对访问该表的所有事务使用SERIALIZABLE
隔离级别。
然后,您只需使用触发器(不带锁),就不会发生异常。如果遇到序列化错误,请重复该事务。
这带来了一定的性能损失,但是比表锁允许更多的并发。它还避免了开始时描述的问题。