137 lines
4.8 KiB
Java
137 lines
4.8 KiB
Java
package com.erp.example.seata;
|
||
|
||
import com.erp.example.seata.entity.Inventory;
|
||
import com.erp.example.seata.entity.InventoryLog;
|
||
import com.erp.example.seata.mapper.InventoryLogMapper;
|
||
import com.erp.example.seata.mapper.InventoryMapper;
|
||
import io.seata.rm.tcc.api.BusinessActionContext;
|
||
import org.slf4j.Logger;
|
||
import org.slf4j.LoggerFactory;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.stereotype.Service;
|
||
import org.springframework.transaction.annotation.Transactional;
|
||
|
||
import java.time.LocalDateTime;
|
||
|
||
/**
|
||
* 库存服务 - AT模式实现
|
||
*/
|
||
@Service
|
||
public class InventoryService {
|
||
|
||
private static final Logger log = LoggerFactory.getLogger(InventoryService.class);
|
||
|
||
@Autowired
|
||
private InventoryMapper inventoryMapper;
|
||
|
||
@Autowired
|
||
private InventoryLogMapper inventoryLogMapper;
|
||
|
||
/**
|
||
* 预留库存(冻结库存)
|
||
* AT模式自动记录前后镜像,异常时自动回滚
|
||
*/
|
||
@Transactional
|
||
public void reserveStock(Long productId, Integer quantity, String orderNo) {
|
||
log.info("预留库存: 商品ID={}, 数量={}, 订单={}", productId, quantity, orderNo);
|
||
|
||
Inventory inventory = inventoryMapper.findByProductId(productId);
|
||
if (inventory == null) {
|
||
throw new RuntimeException("商品不存在: " + productId);
|
||
}
|
||
|
||
Integer availableStock = inventory.getStock() - inventory.getReservedStock();
|
||
if (availableStock < quantity) {
|
||
throw new RuntimeException("库存不足: 可用=" + availableStock + ", 需要=" + quantity);
|
||
}
|
||
|
||
// 冻结库存 = 增加预留数量
|
||
inventory.setReservedStock(inventory.getReservedStock() + quantity);
|
||
inventoryMapper.update(inventory);
|
||
|
||
// 记录库存变动日志
|
||
InventoryLog log = new InventoryLog();
|
||
log.setProductId(productId);
|
||
log.setOrderNo(orderNo);
|
||
log.setChangeType("RESERVE");
|
||
log.setQuantity(quantity);
|
||
log.setBeforeStock(inventory.getStock());
|
||
log.setAfterStock(inventory.getStock());
|
||
log.setCreateTime(LocalDateTime.now());
|
||
inventoryLogMapper.insert(log);
|
||
|
||
log.info("库存预留成功: {}", inventory);
|
||
}
|
||
|
||
/**
|
||
* 释放库存(取消预留)
|
||
* 用于订单取消时回滚
|
||
*/
|
||
@Transactional
|
||
public void releaseStock(Long productId, Integer quantity, String orderNo) {
|
||
log.info("释放库存: 商品ID={}, 数量={}, 订单={}", productId, quantity, orderNo);
|
||
|
||
Inventory inventory = inventoryMapper.findByProductId(productId);
|
||
if (inventory == null) {
|
||
log.warn("商品不存在: {}", productId);
|
||
return;
|
||
}
|
||
|
||
// 释放库存 = 减少预留数量
|
||
inventory.setReservedStock(Math.max(0, inventory.getReservedStock() - quantity));
|
||
inventoryMapper.update(inventory);
|
||
|
||
// 记录库存变动日志
|
||
InventoryLog log = new InventoryLog();
|
||
log.setProductId(productId);
|
||
log.setOrderNo(orderNo);
|
||
log.setChangeType("RELEASE");
|
||
log.setQuantity(quantity);
|
||
log.setBeforeStock(inventory.getStock());
|
||
log.setAfterStock(inventory.getStock());
|
||
log.setCreateTime(LocalDateTime.now());
|
||
inventoryLogMapper.insert(log);
|
||
|
||
log.info("库存释放成功: {}", inventory);
|
||
}
|
||
|
||
/**
|
||
* 扣减库存(正式扣减,释放预留)
|
||
* 订单支付成功后调用
|
||
*/
|
||
@Transactional
|
||
public void consumeStock(Long productId, Integer quantity, String orderNo) {
|
||
log.info("扣减库存: 商品ID={}, 数量={}, 订单={}", productId, quantity, orderNo);
|
||
|
||
Inventory inventory = inventoryMapper.findByProductId(productId);
|
||
if (inventory == null) {
|
||
throw new RuntimeException("商品不存在: " + productId);
|
||
}
|
||
|
||
// 扣减库存 = 减少总库存和预留库存
|
||
inventory.setStock(inventory.getStock() - quantity);
|
||
inventory.setReservedStock(inventory.getReservedStock() - quantity);
|
||
inventoryMapper.update(inventory);
|
||
|
||
// 记录库存变动日志
|
||
InventoryLog inventoryLog = new InventoryLog();
|
||
inventoryLog.setProductId(productId);
|
||
inventoryLog.setOrderNo(orderNo);
|
||
inventoryLog.setChangeType("CONSUME");
|
||
inventoryLog.setQuantity(quantity);
|
||
inventoryLog.setBeforeStock(inventory.getStock() + quantity);
|
||
inventoryLog.setAfterStock(inventory.getStock());
|
||
inventoryLog.setCreateTime(LocalDateTime.now());
|
||
inventoryLogMapper.insert(inventoryLog);
|
||
|
||
log.info("库存扣减成功: {}", inventory);
|
||
}
|
||
|
||
/**
|
||
* 查询商品库存
|
||
*/
|
||
public Inventory findByProductId(Long productId) {
|
||
return inventoryMapper.findByProductId(productId);
|
||
}
|
||
}
|