java 如何锁定库存
锁定库存的实现方法
在Java中锁定库存通常涉及数据库操作和并发控制,以下是几种常见实现方式:
使用数据库事务和悲观锁
通过SELECT FOR UPDATE语句在查询时直接锁定记录:
@Transactional
public boolean lockStock(Long productId, Integer quantity) {
// 查询并锁定库存记录
Stock stock = entityManager.createQuery(
"SELECT s FROM Stock s WHERE s.productId = :pid FOR UPDATE",
Stock.class)
.setParameter("pid", productId)
.getSingleResult();
if (stock.getAvailable() >= quantity) {
stock.setLocked(stock.getLocked() + quantity);
stock.setAvailable(stock.getAvailable() - quantity);
entityManager.persist(stock);
return true;
}
return false;
}
使用乐观锁机制
通过版本号控制实现乐观锁:
@Entity
public class Stock {
@Id
private Long productId;
private Integer available;
private Integer locked;
@Version
private Long version; // 乐观锁版本字段
}
@Transactional
public boolean lockStock(Long productId, Integer quantity) {
Stock stock = stockRepository.findById(productId).orElseThrow();
if (stock.getAvailable() >= quantity) {
stock.setLocked(stock.getLocked() + quantity);
stock.setAvailable(stock.getAvailable() - quantity);
stockRepository.save(stock);
return true;
}
return false;
}
分布式锁实现
使用Redis实现分布式锁:
public boolean lockStockWithRedis(Long productId, Integer quantity) {
String lockKey = "stock_lock:" + productId;
String clientId = UUID.randomUUID().toString();
try {
// 尝试获取锁
Boolean locked = redisTemplate.opsForValue().setIfAbsent(
lockKey, clientId, 30, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
Stock stock = stockRepository.findById(productId).orElseThrow();
if (stock.getAvailable() >= quantity) {
stock.setLocked(stock.getLocked() + quantity);
stock.setAvailable(stock.getAvailable() - quantity);
stockRepository.save(stock);
return true;
}
}
return false;
} finally {
// 释放锁
if (clientId.equals(redisTemplate.opsForValue().get(lockKey))) {
redisTemplate.delete(lockKey);
}
}
}
库存预占表设计
创建单独的预占记录表:

@Entity
public class StockReservation {
@Id
@GeneratedValue
private Long id;
private Long productId;
private Integer quantity;
private String orderId;
private LocalDateTime expireTime;
private Integer status; // 0-预占中 1-已确认 2-已释放
}
注意事项
- 悲观锁可能导致性能问题,特别是在高并发场景
- 乐观锁需要处理版本冲突时的重试机制
- 分布式锁需要确保解锁操作的原子性
- 考虑设置库存预占的过期时间,防止长期锁定
- 实际业务中通常需要结合订单状态进行库存的最终扣减






