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