首页 > 解决方案 > 如何以最佳方式锁定postgres中的数据

问题描述

我有这两个函数充当互斥锁和解锁:

CREATE OR REPLACE FUNCTION get_config (guildid_in int8, key_in varchar) RETURNS jsonb AS $$
    DECLARE d JSONB;
    BEGIN
        WHILE (SELECT locked FROM guild_options WHERE guildid = guildid_in AND key = key_in) LOOP END LOOP;
        UPDATE guild_options SET locked = true WHERE guildid = guildid_in AND key = key_in;
        SELECT data INTO d FROM guild_options WHERE guildid = guildid_in AND key = key_in ;
        REtURN d;
    END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION set_config (guildid_in int8, key_in varchar, data_in jsonb) RETURNS void AS $$
    BEGIN
        UPDATE guild_options SET locked = false, data = data_in WHERE guildid = guildid_in AND key = key_in;
    END;
    $$ LANGUAGE  plpgsql;

我有这两个功能的原因是因为我不希望不同客户端之间的数据竞争覆盖数据等等,这允许我锁定一段数据,修改它然后解锁以供其他客户端读取/更新。我没有使用 postgres 锁(表锁、行锁、咨询锁),因为我需要锁定多个事务的能力,并且因为我在程序中使用数据库池,所以我不能使用咨询锁,因为有多个会话一次连接到数据库,我无法控制哪一个锁定/解锁

有没有更好的方法来做到这一点(比如更好的投票)?

标签: sqlpostgresqllocks

解决方案


您“需要锁定多个事务的能力”。这正是 Postgres 锁的作用。可以在事务或会话级别获取建议锁。您可能还希望将其视为Serializable Isolation Level
顺便说一句:您的功能没有达到您的预期。在get_config您将锁定的列更新为 True,但在您提交之前没有其他会话看到此内容。现在,如果此过程是更大且仅部分完成的事务的一部分,则此处的提交将提交到目前为止完成的所有事务,如果稍后整个事务失败,则您已提交事务的一部分。即使您在更新后提交,仍然有可能在更新和提交之间出现另一个事务(苗条但不是 0)。同样适用该set_config功能。


推荐阅读