There are at least 2 business processes involved here.
Show available seats.
Book a selected seat.
Since these processes don't follow one another immoderately, and since 2 people may select the same seat the concurrency issue arises.
If your database design assigns the correct uniqueness constraint so that the combination of:
-TheaterID
-SeatID
-EventID
are unique, then the database will prevent duplicates.
The following scenario is also possible but will be taken care of by the above suggested implementation:
Assuming a grid view of available for a given theater and a given event can be displayed:
- User1 displays available seats (and gets seats 1 and 2)
- User2 displays available seats (and gets seats 1 and 2)
- User1 talks a bit with the customer on the phone
- User2 goes and books seat 2 for his customer
- User1 tries to book seat 2 for his customer (because it shows as available on his screen)
- The unique index prevents step 5 from commuting the data.
So all what you need to do may be nothing more correct database design and proper choice on constraints.
Other more complex approaches are possible if you want, using transaction queues. In this case, requests are written first to a queue then fires a process every n seconds but that is hardly necessary or practical in your case.
The really interesting part is what should the list grid for user 1 show?