Premium

Inventory Management (REST)

Ten concurrent requests, three units of stock: the naive path oversold every single trial, the fixed one never did.

  • Java
  • Spring Boot
  • MySQL

About this project

A REST API for warehouse or shop stock: create products, receive stock, reserve it for an order, release a reservation that fell through, and see every accepted movement — and every rejected attempt — in a full audit trail. Java 21, Spring Boot 4.1, Spring Data JPA, MySQL, built with the Maven wrapper so a clone-and-build needs nothing but a JDK.

Underneath, it is a project about one guarantee: when stock is nearly gone and two orders both try to claim the last units at the same instant, the database must never confirm more units than actually exist. Rather than assert that the code keeps it, this project puts ten concurrent HTTP requests against three units of real stock and counts what actually happens, with a naive implementation and a fixed one, side by side, against the same running server — the naive path (a raw SQL read-then-write that steps around the entity layer's own @Version column) oversold in 100% of measured trials, confirming all ten requests every time; the fixed path (real JPA optimistic locking with a bounded retry loop) confirmed exactly three and rejected exactly seven, every single trial. Built as a template on purpose: the retry pattern does not know or care that it is managing inventory, and the README's first suggested extension is forking Product onto an entity that has nothing to do with a warehouse, to prove the pattern generalises rather than assume it does.

What you will learn

  • Reproduce a real stock-overselling race condition with concurrent HTTP requests, measured, not simulated
  • Fix it with JPA optimistic locking (@Version) and a bounded retry loop, and explain why over a raw lock
  • Understand the Spring self-invocation/proxy trap that silently defeats @Transactional if you get it wrong
  • Build a global exception handler that returns a real status code for every expected failure, never a raw 500
  • Fork a concurrency-safe pattern onto a different domain entity, and prove the fork still holds under load

Before you start

  • Java and some Spring Boot — controllers, services, Spring Data JPA basics
  • A JDK 21+ — no global Maven install needed, the bundled wrapper downloads its own
  • MySQL 8+ reachable somewhere — the README covers pointing it at your own instance

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.