diff --git a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/IOrderService.java b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/IOrderService.java index 34698e4c5..d062c6a11 100644 --- a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/IOrderService.java +++ b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/IOrderService.java @@ -29,6 +29,11 @@ public interface IOrderService extends IService { */ OrderSubmitVO submit(OrderSubmitDTO orderSubmitDTO) ; + /** + * 订单提交 + */ + OrderSubmitVO submitTcc(OrderSubmitDTO orderSubmitDTO) ; + /** * 订单支付 */ diff --git a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/impl/OrderServiceImpl.java b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/impl/OrderServiceImpl.java index 468d35ddf..aa689d09e 100644 --- a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/impl/OrderServiceImpl.java +++ b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/service/impl/OrderServiceImpl.java @@ -15,17 +15,18 @@ import com.youlai.mall.oms.enums.OrderStatusEnum; import com.youlai.mall.oms.enums.OrderTypeEnum; import com.youlai.mall.oms.enums.PayTypeEnum; import com.youlai.mall.oms.mapper.OrderMapper; -import com.youlai.mall.oms.pojo.entity.OmsOrder; -import com.youlai.mall.oms.pojo.entity.OmsOrderItem; import com.youlai.mall.oms.pojo.dto.OrderConfirmDTO; import com.youlai.mall.oms.pojo.dto.OrderItemDTO; import com.youlai.mall.oms.pojo.dto.OrderSubmitDTO; +import com.youlai.mall.oms.pojo.entity.OmsOrder; +import com.youlai.mall.oms.pojo.entity.OmsOrderItem; import com.youlai.mall.oms.pojo.vo.CartVO; import com.youlai.mall.oms.pojo.vo.OrderConfirmVO; import com.youlai.mall.oms.pojo.vo.OrderSubmitVO; import com.youlai.mall.oms.service.ICartService; import com.youlai.mall.oms.service.IOrderItemService; import com.youlai.mall.oms.service.IOrderService; +import com.youlai.mall.oms.tcc.service.SeataTccOrderService; import com.youlai.mall.pms.api.SkuFeignClient; import com.youlai.mall.pms.pojo.dto.SkuDTO; import com.youlai.mall.pms.pojo.dto.SkuLockDTO; @@ -56,16 +57,17 @@ import static com.youlai.mall.oms.constant.OmsConstants.*; @Service public class OrderServiceImpl extends ServiceImpl implements IOrderService { - private ICartService cartService; - private SkuFeignClient skuFeignService; - private MemberAddressFeignClient addressFeignService; - private IOrderItemService orderItemService; - private RabbitTemplate rabbitTemplate; - private StringRedisTemplate redisTemplate; - private ThreadPoolExecutor threadPoolExecutor; - private MemberFeignClient memberFeignClient; + private final ICartService cartService; + private final SkuFeignClient skuFeignService; + private final MemberAddressFeignClient addressFeignService; + private final IOrderItemService orderItemService; + private final RabbitTemplate rabbitTemplate; + private final StringRedisTemplate redisTemplate; + private final ThreadPoolExecutor threadPoolExecutor; + private final MemberFeignClient memberFeignClient; - private BusinessNoGenerator businessNoGenerator; + private final BusinessNoGenerator businessNoGenerator; + private final SeataTccOrderService seataTccOrderService; /** * 订单确认 @@ -175,7 +177,6 @@ public class OrderServiceImpl extends ServiceImpl impleme if (!Result.success().getCode().equals(lockResult.getCode())) { throw new BizException(Result.failed().getMsg()); } - // 创建订单(状态:待支付) OmsOrder order = new OmsOrder(); order.setOrderSn(orderToken) // 把orderToken赋值给订单编号【!】 @@ -213,6 +214,63 @@ public class OrderServiceImpl extends ServiceImpl impleme return submitVO; } + @Override + @GlobalTransactional(rollbackFor = Exception.class) + public OrderSubmitVO submitTcc(OrderSubmitDTO submitDTO) { + log.info("=======================订单提交=======================\n订单提交信息:{}", submitDTO); + // 订单重复提交校验 + String orderToken = submitDTO.getOrderToken(); + DefaultRedisScript redisScript = new DefaultRedisScript<>(RELEASE_LOCK_LUA_SCRIPT, Long.class); + Long result = this.redisTemplate.execute(redisScript, Collections.singletonList(ORDER_TOKEN_PREFIX + orderToken), orderToken); + + if (!ObjectUtil.equals(result, RELEASE_LOCK_SUCCESS_RESULT)) { + throw new BizException("订单不可重复提交"); + } + + List orderItems = submitDTO.getOrderItems(); + if (CollectionUtil.isEmpty(orderItems)) { + throw new BizException("订单没有商品,请选择商品后提交"); + } + + // 订单验价 + Long currentTotalPrice = orderItems.stream().map(item -> { + SkuDTO sku = skuFeignService.getSkuById(item.getSkuId()).getData(); + if (sku != null) { + return sku.getPrice() * item.getCount(); + } + return 0l; + }).reduce(0l, Long::sum); + + if (currentTotalPrice.compareTo(submitDTO.getTotalPrice()) != 0) { + throw new BizException("页面已过期,请重新刷新页面再提交"); + } + + // 校验库存是否足够和锁库存 + List skuLockList = orderItems.stream() + .map(item -> SkuLockDTO.builder().skuId(item.getSkuId()) + .count(item.getCount()) + .orderToken(orderToken) + .build()) + .collect(Collectors.toList()); + + Result lockResult = skuFeignService.lockStock(skuLockList); + + if (!Result.success().getCode().equals(lockResult.getCode())) { + throw new BizException(Result.failed().getMsg()); + } + // TCC模式创建订单(状态:待支付) + OmsOrder order = seataTccOrderService.prepareSubmitOrder(null, submitDTO); + // 将订单放入延时队列,超时未支付由交换机order.exchange切换到死信队列完成系统自动关单 + log.info("订单超时取消RabbitMQ消息发送,订单SN:{}", orderToken); + rabbitTemplate.convertAndSend("order.exchange", "order.create", orderToken); + + OrderSubmitVO submitVO = new OrderSubmitVO(); + submitVO.setOrderId(order.getId()); + submitVO.setOrderSn(order.getOrderSn()); + log.info("订单提交响应:{}", submitVO.toString()); + return submitVO; + } + /** * 订单支付 @@ -310,5 +368,4 @@ public class OrderServiceImpl extends ServiceImpl impleme page.setRecords(list); return page; } - } diff --git a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/tcc/idempotent/IdempotentUtil.java b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/tcc/idempotent/IdempotentUtil.java new file mode 100644 index 000000000..201f319bb --- /dev/null +++ b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/tcc/idempotent/IdempotentUtil.java @@ -0,0 +1,26 @@ +package com.youlai.mall.oms.tcc.idempotent; + +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; + +/** + * @Author DaniR + * @Description TCC幂等工具类 + * @Date 2021/7/15 20:38 + **/ +public class IdempotentUtil { + + private static Table,String,Long> map= HashBasedTable.create(); + + public static void addMarker(Class clazz,String xid,Long marker){ + map.put(clazz,xid,marker); + } + + public static Long getMarker(Class clazz,String xid){ + return map.get(clazz,xid); + } + + public static void removeMarker(Class clazz,String xid){ + map.remove(clazz,xid); + } +} \ No newline at end of file diff --git a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/tcc/service/SeataTccOrderService.java b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/tcc/service/SeataTccOrderService.java new file mode 100644 index 000000000..6076bc5b0 --- /dev/null +++ b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/tcc/service/SeataTccOrderService.java @@ -0,0 +1,20 @@ +package com.youlai.mall.oms.tcc.service; + +import com.youlai.mall.oms.pojo.dto.OrderSubmitDTO; +import com.youlai.mall.oms.pojo.entity.OmsOrder; +import io.seata.rm.tcc.api.BusinessActionContext; +import io.seata.rm.tcc.api.BusinessActionContextParameter; +import io.seata.rm.tcc.api.LocalTCC; +import io.seata.rm.tcc.api.TwoPhaseBusinessAction; + +@LocalTCC +public interface SeataTccOrderService { + + @TwoPhaseBusinessAction(name = "prepareSubmitOrder", commitMethod = "commitSubmitOrder", rollbackMethod = "rollbackSubmitOrder") + OmsOrder prepareSubmitOrder(BusinessActionContext businessActionContext, + @BusinessActionContextParameter(paramName = "orderSubmitDTO") OrderSubmitDTO orderSubmitDTO); + + boolean commitSubmitOrder(BusinessActionContext businessActionContext); + + boolean rollbackSubmitOrder(BusinessActionContext businessActionContext); +} diff --git a/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/tcc/service/impl/SeataTccOrderServiceImpl.java b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/tcc/service/impl/SeataTccOrderServiceImpl.java new file mode 100644 index 000000000..7b86468fd --- /dev/null +++ b/mall-oms/oms-boot/src/main/java/com/youlai/mall/oms/tcc/service/impl/SeataTccOrderServiceImpl.java @@ -0,0 +1,104 @@ +package com.youlai.mall.oms.tcc.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.youlai.common.web.util.JwtUtils; +import com.youlai.mall.oms.enums.OrderStatusEnum; +import com.youlai.mall.oms.enums.OrderTypeEnum; +import com.youlai.mall.oms.pojo.dto.OrderItemDTO; +import com.youlai.mall.oms.pojo.dto.OrderSubmitDTO; +import com.youlai.mall.oms.pojo.entity.OmsOrder; +import com.youlai.mall.oms.pojo.entity.OmsOrderItem; +import com.youlai.mall.oms.service.IOrderItemService; +import com.youlai.mall.oms.service.IOrderService; +import com.youlai.mall.oms.tcc.idempotent.IdempotentUtil; +import com.youlai.mall.oms.tcc.service.SeataTccOrderService; +import io.seata.rm.tcc.api.BusinessActionContext; +import io.seata.rm.tcc.api.LocalTCC; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +@Slf4j +@LocalTCC +public class SeataTccOrderServiceImpl implements SeataTccOrderService { + @Autowired + private IOrderService orderService; + @Autowired + private IOrderItemService orderItemService; + + @Transactional + @Override + public OmsOrder prepareSubmitOrder(BusinessActionContext businessActionContext, OrderSubmitDTO orderSubmitDTO) { + log.info("==========创建 订单 第一阶段,事务组Xid:{} ==========", businessActionContext.getXid()); + List orderItems = orderSubmitDTO.getOrderItems(); + String orderToken = orderSubmitDTO.getOrderToken(); + // 创建订单(状态:待支付) + OmsOrder order = new OmsOrder(); + order.setOrderSn(orderToken) + .setStatus(OrderStatusEnum.PENDING_PAYMENT.getCode()) + .setSourceType(OrderTypeEnum.APP.getCode()) + .setMemberId(JwtUtils.getUserId()) + .setRemark(orderSubmitDTO.getRemark()) + .setPayAmount(orderSubmitDTO.getPayAmount()) + .setTotalQuantity(orderItems.stream().map(item -> item.getCount()).reduce(0, (x, y) -> x + y)) + .setTotalAmount(orderItems.stream().map(item -> item.getPrice() * item.getCount()).reduce(0l, (x, y) -> x + y)) + .setGmtCreate(new Date()); + orderService.save(order); + // 创建订单商品 + List orderItemList = orderItems.stream().map(item -> OmsOrderItem.builder() + .orderId(order.getId()) + .skuId(item.getSkuId()) + .skuName(item.getSkuName()) + .skuPrice(item.getPrice()) + .skuPic(item.getPic()) + .skuQuantity(item.getCount()) + .skuTotalPrice(item.getCount() * item.getPrice()) + .skuCode(item.getSkuCode()) + .build()).collect(Collectors.toList()); + orderItemService.saveBatch(orderItemList); + log.info("保存订单:{} 成功", order.getOrderSn()); + IdempotentUtil.addMarker(getClass(), businessActionContext.getXid(), System.currentTimeMillis()); + return order; + } + + + @Override + @Transactional + public boolean commitSubmitOrder(BusinessActionContext businessActionContext) { + log.info("==========已经完成Confirm-->创建 订单 第二阶段提交,事务组Xid:{} ==========", businessActionContext.getXid()); + if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) { + log.info("已执行过Confirm阶段"); + return true; + } + IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid()); + return true; + } + + @Override + @Transactional + public boolean rollbackSubmitOrder(BusinessActionContext businessActionContext) { + log.info("======================rollbackSubmitOrder========================"); + if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) { + log.info("已执行过rollback阶段"); + return true; + } + JSONObject jsonObject = (JSONObject) businessActionContext.getActionContext("orderSubmitDTO"); + OrderSubmitDTO orderSubmitDTO = new OrderSubmitDTO(); + BeanUtil.copyProperties(jsonObject, orderSubmitDTO); + OmsOrder omsOrder = orderService.getOne(new LambdaQueryWrapper().eq(OmsOrder::getOrderSn, orderSubmitDTO.getOrderToken())); + if (Objects.nonNull(omsOrder)) { + orderItemService.remove(new LambdaQueryWrapper().eq(OmsOrderItem::getOrderId, omsOrder.getId())); + orderService.deleteOrder(omsOrder.getId()); + } + IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid()); + log.info("========== 已经完成Cancle-->第二阶段回滚,事务组Xid:{} ==========" + businessActionContext.getXid()); + return true; + } +} diff --git a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/IPmsSkuService.java b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/IPmsSkuService.java index 7435f37d0..c829b8640 100644 --- a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/IPmsSkuService.java +++ b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/IPmsSkuService.java @@ -14,6 +14,11 @@ public interface IPmsSkuService extends IService { */ boolean lockStock(List list); + /** + * 锁定库存 + */ + boolean lockStockTcc(List list); + /** * 解锁库存 */ diff --git a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/impl/PmsSkuServiceImpl.java b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/impl/PmsSkuServiceImpl.java index 000a19c8d..12f6d64c3 100644 --- a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/impl/PmsSkuServiceImpl.java +++ b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/impl/PmsSkuServiceImpl.java @@ -13,6 +13,8 @@ import com.youlai.mall.pms.pojo.entity.PmsSku; import com.youlai.mall.pms.pojo.dto.SkuDTO; import com.youlai.mall.pms.pojo.dto.SkuLockDTO; import com.youlai.mall.pms.service.IPmsSkuService; +import com.youlai.mall.pms.tcc.service.SeataTccSkuService; +import io.seata.spring.annotation.GlobalTransactional; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; @@ -35,9 +37,21 @@ public class PmsSkuServiceImpl extends ServiceImpl impleme private RedissonClient redissonClient; + private SeataTccSkuService seataTccSkuService; + + @GlobalTransactional + @Override + public boolean lockStockTcc(List skuLockList) { + + seataTccSkuService.prepareSkuLockList(null,skuLockList); + String orderToken = skuLockList.get(0).getOrderToken(); + redisTemplate.opsForValue().set(LOCKED_STOCK_PREFIX + orderToken, JSONUtil.toJsonStr(skuLockList)); + return true; + } /** * 创建订单时锁定库存 */ + @GlobalTransactional @Override public boolean lockStock(List skuLockList) { log.info("=======================创建订单,开始锁定商品库存======================="); @@ -45,7 +59,7 @@ public class PmsSkuServiceImpl extends ServiceImpl impleme if (CollectionUtil.isEmpty(skuLockList)) { throw new BizException("锁定的商品列表为空"); } - + //prepareSkuLockList(null, skuLockList); // 锁定商品 skuLockList.forEach(item -> { RLock lock = redissonClient.getLock(LOCK_SKU_PREFIX + item.getSkuId()); // 获取商品的分布式锁 @@ -84,6 +98,7 @@ public class PmsSkuServiceImpl extends ServiceImpl impleme return true; } + /** * 订单超时关单解锁库存 */ diff --git a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/tcc/idempotent/IdempotentUtil.java b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/tcc/idempotent/IdempotentUtil.java new file mode 100644 index 000000000..92e79767a --- /dev/null +++ b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/tcc/idempotent/IdempotentUtil.java @@ -0,0 +1,25 @@ +package com.youlai.mall.pms.tcc.idempotent; + +import com.google.common.collect.HashBasedTable; +import com.google.common.collect.Table; +/** + * @Author DaniR + * @Description TCC幂等工具类 + * @Date 2021/7/15 20:38 + **/ +public class IdempotentUtil { + + private static Table,String,Long> map= HashBasedTable.create(); + + public static void addMarker(Class clazz,String xid,Long marker){ + map.put(clazz,xid,marker); + } + + public static Long getMarker(Class clazz,String xid){ + return map.get(clazz,xid); + } + + public static void removeMarker(Class clazz,String xid){ + map.remove(clazz,xid); + } +} \ No newline at end of file diff --git a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/tcc/service/SeataTccSkuService.java b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/tcc/service/SeataTccSkuService.java new file mode 100644 index 000000000..21af89c0c --- /dev/null +++ b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/tcc/service/SeataTccSkuService.java @@ -0,0 +1,21 @@ +package com.youlai.mall.pms.tcc.service; + +import com.youlai.mall.pms.pojo.dto.SkuLockDTO; +import io.seata.rm.tcc.api.BusinessActionContext; +import io.seata.rm.tcc.api.BusinessActionContextParameter; +import io.seata.rm.tcc.api.LocalTCC; +import io.seata.rm.tcc.api.TwoPhaseBusinessAction; + +import java.util.List; + +@LocalTCC +public interface SeataTccSkuService { + + @TwoPhaseBusinessAction(name = "prepareSkuLockList", commitMethod = "commitSkuLockList", rollbackMethod = "rollbackSkuLockList") + boolean prepareSkuLockList(BusinessActionContext businessActionContext, + @BusinessActionContextParameter(paramName = "skuLockList") List skuLockList); + + boolean commitSkuLockList(BusinessActionContext businessActionContext); + + boolean rollbackSkuLockList(BusinessActionContext businessActionContext); +} diff --git a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/tcc/service/impl/SeataTccSkuServiceImpl.java b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/tcc/service/impl/SeataTccSkuServiceImpl.java new file mode 100644 index 000000000..9bd1473eb --- /dev/null +++ b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/tcc/service/impl/SeataTccSkuServiceImpl.java @@ -0,0 +1,110 @@ +package com.youlai.mall.pms.tcc.service.impl; + +import cn.hutool.core.collection.CollectionUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.youlai.common.web.exception.BizException; +import com.youlai.mall.pms.pojo.dto.SkuLockDTO; +import com.youlai.mall.pms.pojo.entity.PmsSku; +import com.youlai.mall.pms.service.IPmsSkuService; +import com.youlai.mall.pms.tcc.idempotent.IdempotentUtil; +import com.youlai.mall.pms.tcc.service.SeataTccSkuService; +import io.seata.rm.tcc.api.BusinessActionContext; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import static com.youlai.mall.pms.common.constant.PmsConstants.LOCK_SKU_PREFIX; + +@Slf4j +@Component +public class SeataTccSkuServiceImpl implements SeataTccSkuService { + + @Autowired + private IPmsSkuService iPmsSkuService; + + @Autowired + private RedissonClient redissonClient; + + @Transactional + @Override + public boolean prepareSkuLockList(BusinessActionContext businessActionContext, List skuLockList) { + log.info("=======================创建订单,开始锁定商品库存======================="); + //防幂等 + if (Objects.nonNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) { + log.info("已执行过try阶段"); + return true; + } + log.info("锁定商品信息:{}", skuLockList.toString()); + if (CollectionUtil.isEmpty(skuLockList)) { + throw new BizException("锁定的商品列表为空"); + } + // 锁定商品 + skuLockList.forEach(item -> { + RLock lock = redissonClient.getLock(LOCK_SKU_PREFIX + item.getSkuId()); // 获取商品的分布式锁 + lock.lock(); + boolean result = iPmsSkuService.update(new LambdaUpdateWrapper() + .setSql("locked_stock = locked_stock + " + item.getCount()) + .eq(PmsSku::getId, item.getSkuId()) + .apply("stock - locked_stock >= {0}", item.getCount()) + ); + item.setLocked(result); + lock.unlock(); + }); + // 锁定失败的商品集合 + List unlockSkuList = skuLockList.stream().filter(item -> !item.getLocked()).collect(Collectors.toList()); + if (CollectionUtil.isNotEmpty(unlockSkuList)) { + // 恢复已被锁定的库存 + List lockSkuList = skuLockList.stream().filter(SkuLockDTO::getLocked).collect(Collectors.toList()); + lockSkuList.forEach(item -> + iPmsSkuService.update(new LambdaUpdateWrapper() + .eq(PmsSku::getId, item.getSkuId()) + .setSql("locked_stock = locked_stock - " + item.getCount())) + ); + // 提示订单哪些商品库存不足 + List ids = unlockSkuList.stream().map(SkuLockDTO::getSkuId).collect(Collectors.toList()); + throw new BizException("商品" + ids.toString() + "库存不足"); + } + IdempotentUtil.addMarker(getClass(), businessActionContext.getXid(), System.currentTimeMillis()); + return true; + } + + @Transactional + @Override + public boolean commitSkuLockList(BusinessActionContext businessActionContext) { + log.info("=====================commitSkuLockList 成功========================="); + if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) { + log.info(businessActionContext.getXid() + ": 已执行过commit阶段"); + return true; + } + IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid()); + return true; + } + + @Transactional + @Override + public boolean rollbackSkuLockList(BusinessActionContext businessActionContext) { + log.info("======================rollbackSkuLockList========================"); + if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) { + log.info(businessActionContext.getXid() + ": 已执行过rollback阶段"); + return true; + } + JSONArray jsonObjectList = (JSONArray) businessActionContext.getActionContext("skuLockList"); + List skuLockList = JSONObject.parseArray(jsonObjectList.toJSONString(), SkuLockDTO.class); + skuLockList.forEach(item -> + iPmsSkuService.update(new LambdaUpdateWrapper() + .eq(PmsSku::getId, item.getSkuId()) + .setSql("locked_stock = locked_stock - " + item.getCount())) + ); + IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid()); + return true; + } +}