postgresql - 哪个显式锁用于触发器?

标签 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 的表中。

最佳答案

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

此外,所有与SHARE UPDATE EXCLUSIVE冲突的表锁都将导致autovacuum取消,当这种情况发生太频繁时会导致表膨胀。

所以远离表锁,它们通常是错误的。

解决此问题的更好方法是完全不使用显式锁定,而是对访问此表的所有事务使用 SERIALIZABLE 隔离级别。

然后你可以简单地使用你的触发器(没有锁),并且不会发生异常。如果出现序列化错误,请重复事务。

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

关于postgresql - 哪个显式锁用于触发器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55653461/

相关文章:

mysql - 如何在插入之前在mysql中创建触发器以将值与时间戳连接起来

sql - 引发异常以禁止更新 PostgreSQL 中的列

PostgreSql 将值存储为整数与 varchar

java - 使用 c3p0 的 JDBC url 中的应用程序名称

multithreading - 如何告诉Hotspot JVM使用单处理器还是多处理器线程同步?

java - 释放锁后强制下一个线程的最短等待时间?

java - Hibernate 外键到串行列

sql - postgreSQL hstore 如果包含值

java - Hibernate 使用准备好的语句进行悲观锁定

mysql - 如何创建从表中获取值并更新不同表的触发器