【问题标题】:Postgresql lock for insert only [duplicate]仅用于插入的 Postgresql 锁 [重复]
【发布时间】:2023-04-07 06:02:01
【问题描述】:

我在 postgresql 中有两个表:

table A: has the definitions for a certain object
table B: has the instances of the objects defined in table A

表 A 有列 total_instancesper_player_instances,它们都可以为空,如果设置了它们,我需要防止表 B 中的实例计数超过。该代码处理大多数情况,但我从并发插入中得到重复。

不需要锁定表 A,因为它很少更改,如果我们这样做,我们可以在表 B 中不会发生插入的计划停机时间内进行。

我编写了一个触发器来计算现有实例并在计数超过时返回错误,但我一定是锁定错误,因为现在我遇到了 deadlock_detected 错误。我的触发函数是这样的:

CREATE OR REPLACE FUNCTION ri_constraints_func() RETURNS trigger AS $$
DECLARE
    max_total          INTEGER   := NULL;
    max_per_player     INTEGER   := NULL;
    total_count        INTEGER   := 0;
    per_player_count   INTEGER   := 0;
BEGIN
    -- prevent concurrent inserts from multiple transactions

    SELECT INTO max_total, max_per_player
           awardable_total, awardable_per_player
    FROM   t1
    WHERE  id = NEW.t1_id;

    LOCK TABLE t2 IN EXCLUSIVE MODE;

    IF max_total IS NOT NULL THEN
        SELECT INTO total_count
               count(1)
        FROM   t2
        WHERE  t1_id = NEW.t1_id;

        IF total_count >= max_total THEN
            RAISE EXCEPTION 'awardable_total_exceeded';
        END IF;
    END IF;

    IF max_per_player IS NOT NULL THEN
        SELECT INTO per_player_count
               count(1)
        FROM   t2
        WHERE  t1_id = NEW.t1_id
        AND    awarded_to_player_id = NEW.awarded_to_player_id;

        IF per_player_count >= max_per_player THEN
            RAISE EXCEPTION 'awardable_per_player_exceeded';
        END IF;
    END IF;

    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

基本上我需要做的是防止在计算实例和执行插入之间插入表。我认为使用LOCK TABLE t2 IN EXCLUSIVE MODE; 可以做到这一点。我正在对表锁定进行更多研究,但如果有人知道使用什么锁定级别来完成此操作,我将不胜感激。

另外,我不喜欢这种特殊的方法,所以如果要让它工作需要重新编写这个函数,我也愿意。

Postgresql 版本是 11。

【问题讨论】:

  • 没有必要明确锁定任何东西。

标签: database postgresql database-deadlocks database-locking


【解决方案1】:

我认为您所做的事情是不必要的,并且可以通过使用适当的事务管理来完成。

对于需要查看整个表的事务,将隔离级别设置为 SERIALIZABLE。这将禁止幽灵,这就是您尝试锁定整个表的原因。

您无需手动锁定。

这可能会有所帮助:https://youtu.be/oI2mxnZbSiA

我建议您阅读有关 postgresql 中的隔离级别的信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-30
    • 2014-01-15
    • 1970-01-01
    相关资源
    最近更新 更多