触发器使用哪个显式锁?

时间:2019-04-12 14:04:53

标签: postgresql locking database-trigger database-concurrency

我试图了解用于触发功能的锁的类型。

简化功能:

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相关的新行添加到表中。

1 个答案:

答案 0 :(得分:1)

如果要防止并发事务修改表,则SHARE锁是正确的。但是,如果两个这样的事务同时运行,则可能导致死锁-每个事务都修改了一些行,并在尝试升级表锁时被另一个阻塞。

此外,所有与SHARE UPDATE EXCLUSIVE冲突的表锁都将导致自动真空取消,这将在频繁发生时导致表膨胀。

因此远离表锁,它们通常是错误的事情。

执行此操作的更好方法是根本不使用任何显式锁定,而对访问该表的所有事务使用SERIALIZABLE隔离级别。

然后,您只需使用触发器(不带锁),就不会发生异常。如果遇到序列化错误,请重复该事务。

这带来了一定的性能损失,但是比表锁允许更多的并发。它还避免了开始时描述的问题。