当前位置:首页 > Java

java 如何锁定库存

2026-03-23 23:41:59Java

锁定库存的实现方法

在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);
        }
    }
}

库存预占表设计

创建单独的预占记录表:

java 如何锁定库存

@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-已释放
}

注意事项

  • 悲观锁可能导致性能问题,特别是在高并发场景
  • 乐观锁需要处理版本冲突时的重试机制
  • 分布式锁需要确保解锁操作的原子性
  • 考虑设置库存预占的过期时间,防止长期锁定
  • 实际业务中通常需要结合订单状态进行库存的最终扣减

标签: 库存java
分享给朋友:

相关文章

java程序如何运行

java程序如何运行

编写Java代码 使用文本编辑器或IDE(如IntelliJ IDEA、Eclipse)编写Java源代码,保存为.java文件。例如: public class HelloWorld {…

java如何调用接口

java如何调用接口

调用接口的基本方法 在Java中调用接口通常涉及实现接口或使用接口引用对象。以下是几种常见场景的示例: 定义接口 public interface MyInterface { void d…

java如何自学

java如何自学

确定学习目标和路径 自学Java需要明确目标,例如开发Web应用、Android应用或后端服务。根据目标选择学习重点,如Java基础、Spring框架或Android开发。制定阶段性计划,从基础语法到…

java如何输出数组

java如何输出数组

输出数组的方法 在Java中,输出数组内容有多种方式,具体取决于数组类型和输出格式需求。以下是几种常见的方法: 使用Arrays.toString()方法 适用于一维数组,直接调用Arrays.to…

如何编写java

如何编写java

编写Java程序的基本步骤 安装Java开发工具包(JDK),确保系统环境变量配置正确。可以从Oracle官网下载最新版本的JDK并进行安装。 选择一个合适的集成开发环境(IDE),如Eclipse…

如何搭建java开发环境

如何搭建java开发环境

下载并安装JDK 从Oracle官网或OpenJDK下载适合操作系统的JDK版本。运行安装程序并按照提示完成安装,建议选择默认路径以减少配置复杂度。 配置环境变量 在系统环境变量中添加JAVA_HO…