Careeroza
Real World Example
Flash Sale Stock Reservation
During a "Big Billion Days" style sale, thousands of users hit "Buy" on the same phone in the same second. ShopEase uses three layers: an atomic stock update for the hot path, optimistic locking for order edits, and SKIP LOCKED workers for payment follow-up.
@Service
@RequiredArgsConstructor
public class CheckoutService {
private final ProductRepository products;
private final OrderRepository orders;
@Transactional
public Order placeOrder(User user, List<CartItem> cart) {
// 1. Reserve stock atomically, in product-id order (no lost updates, no deadlocks)
List<CartItem> sorted = cart.stream()
.sorted(Comparator.comparing(ci -> ci.getProduct().getId()))
.toList();
for (CartItem item : sorted) {
int updated = products.decrementStock(item.getProduct().getId(), item.getQuantity());
if (updated == 0) throw new OutOfStockException(item.getProduct().getId());
}
// 2. Create the order (Order has @Version for later status changes)
Order order = Order.from(user, sorted);
return orders.save(order);
}
}
@Component
@RequiredArgsConstructor
class PaymentCheckWorker {
private final OrderRepository orders;
private final PaymentGateway gateway;
@Scheduled(fixedDelay = 2000)
@Transactional
public void run() {
// each app instance gets different rows thanks to SKIP LOCKED
for (Order o : orders.pickBatch(PageRequest.of(0, 20))) {
o.setStatus(gateway.isPaid(o.getPaymentRef()) ? OrderStatus.PAID : OrderStatus.PAYMENT_FAILED);
}
}
}Result Under Load
Load Test
A load test with 500 parallel buyers for a product with 100 units:
k6 run --vus 500 --iterations 500 flash-sale.jsExample output
checks.........................: 100.00% ✓ status is 201 ................ 100 ✓ status is 409 (sold out) ..... 400 products.stock (id=7) .........: 0 <- never negative, never lost deadlocks .....................: 0
Tip: For very hot items, big sites also put stock counters in Redis (atomic DECR) and sync to the database asynchronously. The database pattern above is still the source of truth.