锁定表中的行以进行SELECT和UPDATE

Ger*_*umm 5 sql postgresql database-design

我正在写一个需要预订电影院座位的剧本.

  1. 用户要求2个席位
  2. 如果有2个座位可用,系统会将它们提供给客户
  3. 客户可以接受或要求另外2个席位.
  4. 当他最终接受时,座位被标记为"已售出"

由于可能有多个用户同时使用系统,我需要一种方法来"锁定"提供给当前客户端的行,直到某个时间过去,或者他请求另一个席位.

目前我将提供的座位标记为"已锁定"客户端ID,并使用SELECT将它们返回给客户端(这是针对MySQL,但目标数据库是Postgres)

UPDATE seats SET status = "locked", lock_time = NOW(), lock_id = "lock1" LIMIT 2
SELECT * FROM seats WHERE lock_id = "lock1" AND lock_time > DATE_SUB(NOW(), INTERVAL 2 MINUTE)
Run Code Online (Sandbox Code Playgroud)

有一个问题:如果只有一个座位可用,它仍然会被标记为"已锁定",我将立即释放锁定.

我也很确定有更聪明的方法.处理这样的任务的正确方法是什么?

nat*_*e c 0

竞争条件 - 我认为这作为插入而不是更新会更好。两个更新可以同时运行,并且不会相互冲突。如果您有“锁定座位”表,那么您可以引用 Seat_id 并使其唯一。这样竞争条件就会失败。但是,无论如何,我将其写为更新,就像您在问题中所做的那样,尽管您可以将其更改为插入。

如果没有足够的可用座位,您似乎一开始就不希望能够锁定座位。使用自连接这很容易:

create temp table seats
(
    id          serial,
    event_id    integer,
    locked      boolean default false
);
insert into seats (event_id) values (1),(1),(1),(2);
-- this will not lock event_id = 2 since it will not have a high enough count
update seats
set locked = true
from
(
    -- get the counts so we can drop events without enough seats
    select count(*), event_id from seats group by event_id
) as sum,
(
    -- you can not put limits in update; need to self-join
    select id from seats limit 2
) as t
where sum.event_id = seats.event_id
and seats.id = t.id
and count >= 2
Run Code Online (Sandbox Code Playgroud)

;

UPDATE 2
 id | event_id | locked 
----+----------+--------
  3 |        1 | f
  4 |        2 | f
  2 |        1 | t
  1 |        1 | t
(4 rows)
Run Code Online (Sandbox Code Playgroud)

因此,这会为每个至少有两个座位的活动“锁定”两个座位:)