首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >函数内的Postgres咨询锁允许并发执行

函数内的Postgres咨询锁允许并发执行
EN

Stack Overflow用户
提问于 2016-05-05 18:22:00
回答 1查看 1.5K关注 0票数 6

我遇到了一个问题,在这个问题中,我有一个函数,它需要依赖于某些情况的序列化访问。这似乎是使用咨询锁的一个很好的例子。但是,在相当重的负载下,我发现序列化的访问没有发生,而且我看到了对函数的并发访问。

这一职能的目的是为某一事件提供“库存控制”。这意味着,它的意图是限制对给定事件的同时购票,使事件不会被超卖。这些是应用程序/数据库中使用的唯一建议锁。

我发现,在一个事件中偶尔会有比eventTicketMax值更多的票。这似乎是不可能的,因为咨询锁。当使用低容量的测试(或者在获得锁后手动引入延迟,例如pg_sleep )时,事情会像预期的那样工作。

代码语言:javascript
复制
CREATE OR REPLACE FUNCTION createTicket(
        userId int,
        eventId int,
        eventTicketMax int
    ) RETURNS integer AS $$
        DECLARE insertedId int;
        DECLARE numTickets int;
    BEGIN
            -- first get the event lock
            PERFORM pg_advisory_lock(eventId);

            -- make sure we aren't over ticket max
            numTickets := (SELECT count(*) FROM api_ticket
                WHERE event_id = eventId and status <> 'x');

            IF numTickets >= eventTicketMax THEN
                -- raise an exception if this puts us over the max
                -- and bail
                PERFORM pg_advisory_unlock(eventId);
                RAISE EXCEPTION 'Maximum entries number for this event has been reached.';
            END IF;

            -- create the ticket
            INSERT INTO api_ticket (
                user_id,
                event_id,
                created_ts
            )
            VALUES (
                userId,
                eventId,
                now()
            )
            RETURNING id INTO insertedId;

            -- update the ticket count
            UPDATE api_event SET ticket_count = numTickets + 1 WHERE id = eventId;

            -- release the event lock
            PERFORM pg_advisory_unlock(eventId);

        RETURN insertedId;
    END;
    $$ LANGUAGE plpgsql;

下面是我的环境设置:

  • Django 1.8.1 (django.db.backends.postgresql_psycopg2 w/ CONN_MAX_AGE 300)
  • PGBouncer 1.7.2 (会话模式)
  • Postgres 9.3.10在Amazon上

我尝试调优的其他变量:

  • 将CONN_MAX_AGE设置为0
  • 移除弹跳器并直接连接到DB

在我的测试中,我注意到,在某个活动被超卖的情况下,门票是从不同的网络服务器上购买的,所以我不认为共享会话有什么有趣的事情,但我不能肯定。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-05-05 19:52:22

一旦执行PERFORM pg_advisory_unlock(eventId),另一个会话就可以获取该锁,但是由于会话#1的插入尚未完成,因此它不会被计算在会话#2的COUNT(*)中,从而导致超额预订。

如果保留建议锁策略,则必须使用事务级建议锁(pg_advisory_xact_lock),而不是会话级别。这些锁在提交时自动释放。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37057616

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档