代码分析:乐观锁库存冻结操作
基于 MyBatisDisposeUtil.java 的分析,这段代码实现了带乐观锁的库存冻结功能。
核心功能
这是一个**库存预留(冻结)**操作,用于在业务订单处理时锁定一定数量的库存,防止超卖。
方法参数解析
| 参数 |
作用 |
oriStock |
原始库存对象(首次尝试使用) |
| 第1个Lambda |
从数据库获取最新库存数据(重试时使用) |
| 第2个Lambda |
核心业务逻辑:校验库存→扣减可用库存→增加冻结库存→创建冻结记录 |
| 第3个Lambda |
失败时生成异常信息 |
业务逻辑流程
- 库存校验:检查可用库存是否充足(
availableQty >= freezeQty)
- 库存调整:
- 可用库存减少:
availableQty - freezeQty
- 冻结库存增加:
frozenQty + freezeQty
- 创建冻结记录:插入
StoreStockFrozen 记录,包含:
- 冻结数量、类型、原因
- 关联的订单信息(订单号、明细ID等)
- 更新库存:持久化修改后的库存数据
乐观锁机制
首次尝试 → 使用原始数据
↓ 失败(版本号冲突)
重试(最多10次) → 新开事务获取最新数据 → 执行业务逻辑
↓ 成功
返回
↓ 全部失败
抛出异常
- 最大重试次数:10次
- 重试间隔:1000ms
- 事务策略:
REQUIRES_NEW 确保每次重试都是独立事务
异常处理
当所有重试都失败时,抛出包含件号(PN)、序号(SN)、标签号的详细错误信息,便于定位问题。
总结
这段代码通过乐观锁+自动重试机制,确保在高并发场景下库存扣减的准确性和数据一致性,是电商/仓储系统中常见的库存防超卖解决方案。
myBatisDisposeUtil.execOptimisticLockFn(oriStock,() -> {
return getById(stockDto.getPkid());
}, (dto) -> {
if (dto == null){
dto = byId;
}
if (dto.getAvailableQty().compareTo(freezeQty) < 0) {
throw new BusinessException(StorageResultCode.STORAGE_FREEZE_QTY1);
}
dto.setAvailableQty(dto.getAvailableQty().subtract(freezeQty));
dto.setFrozenQty(dto.getFrozenQty().add(freezeQty));
StoreStockFrozen frozen = new StoreStockFrozen();
frozen.setStoreStockPkid(dto.getPkid());
storeStockFrozenService.insertSelectiveWithLoginUser(frozen, userInfo);
return updateByPrimaryWithLoginUser(dto, userInfo) > 0;
}, (dto) -> {
if (ObjectUtil.isNull(dto)) {
return new BusinessException(500, "操作失败, 处理库存失败!");
}
return new BusinessException(500, StrUtil.format("操作失败, 件{},{} {} 处理库存错误!", dto.getPn(), StrUtil.emptyIfNull(dto.getSn()), dto.getTagNo()));
});