电商系统超卖问题通常是由于在高并发情况下,多个请求同时读取库存并尝试扣减,而库存扣减操作没有进行适当的同步控制,导致库存数据不一致。以下是几种常见的解决方案:
悲观锁
原理:通过同步关键字 `synchronized` 或数据库的行级锁(如 `SELECT ... FOR UPDATE`)来限制并发访问,确保同一时间只有一个请求能够修改库存。
缺点:可能导致用户体验下降,因为用户可能需要等待很长时间才能完成购买。
示例代码:
```java
@Transactional
public void processOrder(Order order) {
synchronized (this) {
int availableStock = inventoryService.getAvailableStock(order.getProductId());
if (availableStock >= order.getQuantity()) {
// 扣减库存
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
// 创建订单
createOrder(order);
} else {
throw new InsufficientStockException("库存不足");
}
}
}
```
乐观锁
原理:利用版本号或时间戳机制,在更新库存时检查数据是否被其他请求修改。通常结合数据库事务和Redis等缓存系统实现。
优点:性能较高,不会阻塞其他请求。
示例代码:
```java
@Transactional
public void processOrder(Order order) {
// 获取当前库存和版本号
Stock currentStock = inventoryService.getStockWithVersion(order.getProductId());
if (currentStock.getAvailableStock() >= order.getQuantity()) {
// 创建订单
createOrder(order);
// 更新库存和版本号
inventoryService.updateStockWithVersion(order.getProductId(), currentStock.getQuantity() - order.getQuantity(), currentStock.getVersion());
} else {
throw new InsufficientStockException("库存不足");
}
}
```
实时库存更新
原理:在用户提交订单时,将库存的扣减与订单创建放在同一个事务中,确保操作的原子性。
示例代码:
```java
@Transactional
public void processOrder(Order order) {
int availableStock = inventoryService.getAvailableStock(order.getProductId());
if (availableStock >= order.getQuantity()) {
// 扣减库存
inventoryService.reduceStock(order.getProductId(), order.getQuantity());
// 创建订单
createOrder(order);
} else {
throw new InsufficientStockException("库存不足");
}
}
```
使用Redis单线程特性
原理:利用Redis的单线程特性,确保在并发情况下库存扣减操作的原子性。
示例代码:
```java
public void reduceStockWithRedis(String productId, int quantity) {
String lockKey = "lock:" + productId;
Boolean lockAcquired = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked");
if (lockAcquired != null && lockAcquired) {
try {
int currentStock = Integer.parseInt(redisTemplate.opsForValue().get(productId));
if (currentStock >= quantity) {
redisTemplate.opsForValue().set(productId, String.valueOf(currentStock - quantity));
// 创建订单
createOrder(productId, quantity);
} else {
throw new InsufficientStockException("库存不足");
}
} finally {
redisTemplate.delete(lockKey);
}
} else {
throw new RuntimeException("库存操作被其他请求锁定");
}
}
```
设置预警库存
原理:在仓库库存和店铺SKU库存一致的同时,设置预警库存,当库存接近预警值时,限制购买数量或自动下架商品。
示例代码: