Database bugs in code

Why two simultaneous clicks on "Purchase" can sell the same concert ticket twice.

The idea

Databases can process thousands of queries a second. If two users buy the last ticket at the exact same millisecond, the database runs their transactions concurrently (interleaved). If they both READ the `tickets_left = 1` before either has a chance to WRITE `tickets_left = 0`, they both succeed. This is a Lost Update anomaly.

To fix this, you don't just rely on standard transactions (which often default to weak "Read Committed" isolation). You must explicitly lock the row using a SELECT ... FOR UPDATE. This forces the second transaction to wait until the first one is completely finished.

DB: tickets_left 1 User A (Tx 1) User B (Tx 2) Row Locked!
Two users try to buy the last 1 ticket at the exact same time.

How it works (Pessimistic Row Locking)

# BAD: Naive read-modify-write
with db.transaction():
    ticket = db.query("SELECT tickets_left FROM events WHERE id=1")
    if ticket.tickets_left > 0:
        # If Tx2 reads before Tx1 reaches here, both buy the ticket!
        db.execute("UPDATE events SET tickets_left = tickets_left - 1")
        return "Purchased!"

# GOOD: SELECT FOR UPDATE
with db.transaction():
    # The database LOCKS this specific row. Tx2 must wait!
    ticket = db.query("SELECT tickets_left FROM events WHERE id=1 FOR UPDATE")
    
    if ticket.tickets_left > 0:
        db.execute("UPDATE events SET tickets_left = tickets_left - 1")
        return "Purchased!"
    else:
        return "Sold out!"