Movie Ticket Booking
Entities: City → Cinema → Screen → Show, aur Seat, Booking, Payment. Yahan sabse important cheez SEAT LOCKING hai. Jab user seat select karta hai to wo TEMPORARILY lock honi chahiye (5-10 minute) — permanently nahi, warna payment chhodne par seat hamesha ke liye block ho jaayegi.
Do logon ke ek saath same seat maangne ka jawab tayyar rakho: database par SELECT ... FOR UPDATE (pessimistic) ya version column (optimistic) — ya Redis mein TTL waala lock. TTL waala approach batana sabse strong hai kyunki expiry APNE AAP ho jaati hai, koi cleanup job nahi chahiye.
enum SeatStatus { AVAILABLE, LOCKED, BOOKED }
class SeatLockService {
// Redis: SET seat:{showId}:{seatId} userId NX EX 600
boolean lock(String showId, String seatId, String userId) {
return redis.setIfAbsent(key(showId, seatId), userId, Duration.ofMinutes(10));
}
// Payment success -> LOCKED se BOOKED, lock hata do
// Payment fail/timeout -> TTL khud expire, seat wapas available
}- Hierarchy: City → Cinema → Screen → Show → Seat
- Seat lock TEMPORARY ho with TTL, permanent nahi
- Redis TTL lock sabse clean — expiry automatic, cleanup job nahi chahiye
PESSIMISTIC LOCK (SELECT ... FOR UPDATE): row lock ho jaati hai, doosra wait karta hai. Correct hai par DB par load daalta hai aur lock zyada der pakadna scalability maar deta hai.
OPTIMISTIC LOCK (version column): update karte waqt version match karo, mismatch par retry. Achha hai jab conflict KAM ho — par blockbuster movie ki first-day booking mein conflict bahut zyada hote hain.
DISTRIBUTED LOCK WITH TTL (Redis): sabse practical. SET NX EX se lock lo, expiry apne aap ho jaati hai. Payment fail hone par cleanup job nahi chahiye — yahi is problem ka best answer hai.
// Redis: lock milega sirf tab jab key exist na kare
Boolean acquired = redis.opsForValue()
.setIfAbsent("seat:" + showId + ":" + seatId, userId, Duration.ofMinutes(10));
// Confirm: LOCKED -> BOOKED, lock delete
// Timeout : TTL expire, seat apne aap wapas AVAILABLESeat SCREEN se judi hoti hai (physical kursi), par booking SHOW se judi hoti hai (us particular time ka slot). Isliye "seat booked hai" ek Show-level fact hai, Seat-level nahi — ek hi kursi 6 PM show mein booked aur 9 PM show mein available ho sakti hai.
Ye galti bahut common hai: log Seat par hi status rakh dete hain aur phir do shows ka data aapas mein mix ho jaata hai. ShowSeat naam ki alag entity banana sabse saaf solution hai.
class Seat { String id; int row, number; SeatCategory category; } // physical
class ShowSeat { // per-show status
Show show; Seat seat; SeatStatus status; Money price;
}