Implementing High-Concurrency Product Flash Sale System with Spring Boot
System Initialization
Initialize product inventory in Redis for caching:
@RestController
public class FlashSaleController {
@Autowired
private RequestAggregatorService aggregator;
@Autowired
private RedisTemplate<String, Object> cache;
@PostMapping("/purchase")
public ApiResponse processPurchase(
@RequestParam("customerId") Integer customerId,
@RequestParam("itemId") Integer itemId) throws InterruptedException {
// Simulate authentication delay
Thread.sleep(200);
Integer availableStock = (Integer) cache.opsForValue()
.get(CacheKeys.ITEM_STOCK_PREFIX + itemId);
if (availableStock != null && availableStock > 0) {
boolean result = aggregator.processRequest(customerId, itemId);
return result ? ApiResponse.success("Purchase completed") :
ApiResponse.failure("Purchase failed");
}
return ApiResponse.failure("Insufficient stock");
}
}
Concurrent Request Aggregation
Custom thread pool implementation to batch process concurrent requests:
@Service
public class RequestAggregatorService {
private final ExecutorService processingPool;
private final TransactionHandler handler;
public boolean processRequest(Integer customerId, Integer itemId) {
Future<Boolean> task = processingPool.submit(
() -> handler.executeTransaction(itemId, customerId)
);
try {
if (task.isDone()) {
Boolean outcome = task.get(1, TimeUnit.SECONDS);
log.info("Transaction outcome: {}", outcome);
return outcome;
}
log.warn("Transaction timeout");
return false;
} catch (TimeoutException e) {
log.error("Processing timeout: {}", e.getMessage());
return false;
} catch (Exception e) {
log.error("Processing error", e);
return false;
}
}
}
Transaction Management with Database Locking
Implementation using databace row-level locking mechanism:
@Service
public class TransactionHandler {
@Transactional(rollbackFor = Exception.class,
propagation = Propagation.REQUIRED,
isolation = Isolation.SERIALIZABLE)
public Boolean executeTransaction(Integer itemId, Integer customerId) {
try {
// Acquire database row lock using FOR UPDATE
Item targetItem = itemRepository.query()
.eq("item_id", itemId)
.last("FOR UPDATE")
.single();
if (targetItem.getAvailableQuantity() < 1) {
return false;
}
// Decrease inventory
int updatedStock = targetItem.getAvailableQuantity() - 1;
UpdateWrapper<Item> updateCondition = new UpdateWrapper<Item>()
.eq("item_id", itemId)
.ge("available_quantity", 1)
.set("available_quantity", updatedStock);
boolean updateSuccess = itemRepository.update(updateCondition);
if (updateSuccess) {
// Update cache
cache.opsForValue().decrement(CacheKeys.ITEM_STOCK_PREFIX + itemId);
// Create order records
PurchaseOrder newOrder = new PurchaseOrder();
newOrder.setCustomerId(customerId.longValue());
newOrder.setStatus(OrderStatus.CONFIRMED);
newOrder.setTimestamp(new Timestamp(System.currentTimeMillis()));
boolean orderCreated = orderRepository.save(newOrder);
OrderDetail detail = new OrderDetail();
detail.setOrderId(newOrder.getId());
detail.setItemId(itemId.longValue());
detail.setAmount(1);
boolean detailCreated = orderDetailRepository.save(detail);
return orderCreated && detailCreated;
}
return false;
} catch (Exception e) {
log.error("Transaction exception: {}", e.getMessage());
return false;
}
}
}
Performance testing demonstrates stable operation under high-concurrency scenarios.