Railway Reservation System
Two threads, one seat: the double-booking race condition proven broken, then proven fixed, with real thread counts both times.
- Java
- JDBC
- MySQL
About this project
List trains, check availability, book a seat, cancel a booking, and a waiting list that promotes automatically when a confirmed seat opens up. Plain Java with JDBC against MySQL — no Spring, no build tool.
The project exists to prove one guarantee: a seat sold to one passenger must never be sold to another, even when two people book in the same instant. Run Reservation --race and two threads race for the last seat on a disposable test train, over and over. The naive version — SELECT, decide in Java, UPDATE, no lock, no transaction — double-books close to every single trial, measured across thousands of real runs at roughly 99 to 100 percent. The fixed version — one atomic UPDATE ... WHERE seats_available > 0 inside a transaction — has never double-booked once across the same scale of testing.
Both numbers are presented as honest, measured ranges, not a single suspiciously round claim: an earlier draft of this README overstated the naive version as failing "every single trial" and the fixed version’s win-split as bounded tighter than measurement actually showed. Both were caught by rerunning the demonstration and rewritten to match what the program actually does — which is itself a small lesson in why you verify a claim about a race condition by running it many times, not once.
What you will learn
- Reproduce a real double-booking race condition with two threads and one seat, measured, not simulated
- Fix it with a single atomic UPDATE ... WHERE guarded by an affected-row check, inside a transaction
- Understand why READ COMMITTED is the isolation level that matters here, and what it guarantees
- Build a waiting list that promotes automatically and correctly on cancellation
- Treat a race condition as a statistical claim to measure across many trials, not a one-off demo to stage
Before you start
- Java basics — classes, exceptions, and a little threading
- MySQL 8 and the MySQL Connector/J JDBC driver — the README gives the one-file download
New to Java? The free Java course covers everything this project assumes.
Academic integrity notice
These projects are provided for learning, experimentation and reference. Understand the code, modify it for your own requirements, and acknowledge external work according to your institution’s academic policies. Priodemy does not supply work to be submitted as your own.
Features
- A real, runnable two-thread race condition demonstration with a naive and a fixed booking method
- Measured double-booking rates across thousands of trials, reported as honest ranges
- An atomic UPDATE ... WHERE fix inside a transaction, with the isolation level explained
- Automatic waiting-list promotion on cancellation, verified end to end
- PNR-based lookup, name-length validation matching the schema, safe double-cancel handling
- Real Indian train data — routes, names and numbers — for ten sample trains
Technology stack
Track: Java · Level: Mini project
What is included
- Reservation.java, Train.java, Booking.java and Db.java — commented throughout
- A README on the race condition, the fix, and the measured evidence for both
- Suggested extensions, including seat classes and fare calculation
Delivered as a 29 KB ZIP. SHA-256 published under Changelog so you can verify it.
System requirements
- Operating system
- Any
- Runtime
- JDK 17+. MySQL 8. MySQL Connector/J JDBC driver (one-file download, linked in the README).
Licence
Learn from it, change it, and use it in your own coursework and personal projects. Do not resell it or pass it off as your own original work.
- Personal and educational use
- Modifying the code however you like
- Using it as the basis of your own coursework, with honest acknowledgement
- Putting your modified version in a portfolio or on your own GitHub
- Reselling or redistributing the project, modified or not
- Presenting it as your own original work
- Commercial deployment — see the Commercial licence
Support window: 6 months from download.
Frequently asked
Is the race condition really reproduced, or just described?
Reproduced. Reservation --race starts two real threads against a real MySQL server and reports what actually happened, every time you run it. The README’s numbers come from thousands of real trials, not a single staged run.
Does the naive version always double-book?
Almost always, not always — and the README says so precisely, because that distinction is itself the lesson: a race condition is a probability, not a certainty, and reporting it as a guaranteed 100% would be exactly the kind of overclaim this project exists to warn against.
Why JDBC instead of Spring Data or Hibernate?
Because the transaction and the atomic UPDATE are the entire point, and an ORM would hide both behind an abstraction. Plain JDBC keeps the fix visible in four lines you can read end to end.
Changelog
- First release
SHA-2561e1d188a9d85a27a80744bda858316a8e42212e1488830f2362eba1315f0a65f