I am writing a script that needs to book seats in the cinema.
- User asks for 2 seats
- If there are 2 seats available, system offers them to client
- Client can either accept them or request another 2 seats.
- When he finally accepts, seats are marked as “sold”
Since there can be multiple users using system simultaneously, I need a way to “lock” the rows offered to current client until certain time passes, or he requests another seats.
Currently I am marking offered seats as “locked” with a client id, and use SELECT to return them to the client (this is for MySQL, but target database is 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)
There is a problem with that: if there’s only 1 seat available, it will still be marked as “locked” and I will have to release lock right away.
I am also pretty sure that there is a smarter way of doing that. What is the correct way of dealing with a task like that?
Race Condition – I think this would be better as an insert rather than an update. Two updates can run at the same time and they will not conflict with each other. If you had ‘locked seats’ table then you could reference the seat_id and make it unique. That way a race conditions would fail. But, in any case, I wrote this as an update as you have in the question although you could change it to an insert.
It seems like you just do not want to be able to lock the seats in the first place if there are not enough available. This is easy with self joins:
;
So this ‘locks’ two seats for every event that has at least two seats 🙂