feat(OrderServiceImpl.java): SeatsAT->TCC模式改造

1、提交订单功能充AT模式可以切换到TCC模式
2、对应的冻结库存TCC模式添加
3、相关功能测试(异常回滚的执行)

Closes #I414QN
This commit is contained in:
DaniR 2021-07-17 10:54:48 +08:00
parent f6e5e6bd07
commit 4b091b20dd
4 changed files with 26 additions and 32 deletions

View File

@ -37,6 +37,7 @@ import io.seata.spring.annotation.GlobalTransactional;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript; import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -67,7 +68,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
private final MemberFeignClient memberFeignClient; private final MemberFeignClient memberFeignClient;
private final BusinessNoGenerator businessNoGenerator; private final BusinessNoGenerator businessNoGenerator;
private final SeataTccOrderService seataTccOrderService; private SeataTccOrderService seataTccOrderService;
/** /**
* 订单确认 * 订单确认
@ -220,12 +221,12 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
log.info("=======================订单提交=======================\n订单提交信息{}", submitDTO); log.info("=======================订单提交=======================\n订单提交信息{}", submitDTO);
// 订单重复提交校验 // 订单重复提交校验
String orderToken = submitDTO.getOrderToken(); String orderToken = submitDTO.getOrderToken();
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_LUA_SCRIPT, Long.class); // DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_LUA_SCRIPT, Long.class);
Long result = this.redisTemplate.execute(redisScript, Collections.singletonList(ORDER_TOKEN_PREFIX + orderToken), orderToken); // Long result = this.redisTemplate.execute(redisScript, Collections.singletonList(ORDER_TOKEN_PREFIX + orderToken), orderToken);
//
if (!ObjectUtil.equals(result, RELEASE_LOCK_SUCCESS_RESULT)) { // if (!ObjectUtil.equals(result, RELEASE_LOCK_SUCCESS_RESULT)) {
throw new BizException("订单不可重复提交"); // throw new BizException("订单不可重复提交");
} // }
List<OrderItemDTO> orderItems = submitDTO.getOrderItems(); List<OrderItemDTO> orderItems = submitDTO.getOrderItems();
if (CollectionUtil.isEmpty(orderItems)) { if (CollectionUtil.isEmpty(orderItems)) {

View File

@ -6,18 +6,18 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.youlai.common.web.util.JwtUtils; import com.youlai.common.web.util.JwtUtils;
import com.youlai.mall.oms.enums.OrderStatusEnum; import com.youlai.mall.oms.enums.OrderStatusEnum;
import com.youlai.mall.oms.enums.OrderTypeEnum; import com.youlai.mall.oms.enums.OrderTypeEnum;
import com.youlai.mall.oms.mapper.OrderMapper;
import com.youlai.mall.oms.pojo.dto.OrderItemDTO; import com.youlai.mall.oms.pojo.dto.OrderItemDTO;
import com.youlai.mall.oms.pojo.dto.OrderSubmitDTO; import com.youlai.mall.oms.pojo.dto.OrderSubmitDTO;
import com.youlai.mall.oms.pojo.entity.OmsOrder; import com.youlai.mall.oms.pojo.entity.OmsOrder;
import com.youlai.mall.oms.pojo.entity.OmsOrderItem; import com.youlai.mall.oms.pojo.entity.OmsOrderItem;
import com.youlai.mall.oms.service.IOrderItemService; 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.idempotent.IdempotentUtil;
import com.youlai.mall.oms.tcc.service.SeataTccOrderService; import com.youlai.mall.oms.tcc.service.SeataTccOrderService;
import io.seata.rm.tcc.api.BusinessActionContext; import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.LocalTCC;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.Date; import java.util.Date;
@ -26,10 +26,11 @@ import java.util.Objects;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j @Slf4j
@LocalTCC @Component
public class SeataTccOrderServiceImpl implements SeataTccOrderService { public class SeataTccOrderServiceImpl implements SeataTccOrderService {
@Autowired @Autowired
private IOrderService orderService; private OrderMapper orderMapper;
@Autowired @Autowired
private IOrderItemService orderItemService; private IOrderItemService orderItemService;
@ -50,7 +51,8 @@ public class SeataTccOrderServiceImpl implements SeataTccOrderService {
.setTotalQuantity(orderItems.stream().map(item -> item.getCount()).reduce(0, (x, y) -> x + y)) .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)) .setTotalAmount(orderItems.stream().map(item -> item.getPrice() * item.getCount()).reduce(0l, (x, y) -> x + y))
.setGmtCreate(new Date()); .setGmtCreate(new Date());
orderService.save(order); orderMapper.insert(order);
int i = 1 / 0;
// 创建订单商品 // 创建订单商品
List<OmsOrderItem> orderItemList = orderItems.stream().map(item -> OmsOrderItem.builder() List<OmsOrderItem> orderItemList = orderItems.stream().map(item -> OmsOrderItem.builder()
.orderId(order.getId()) .orderId(order.getId())
@ -72,9 +74,8 @@ public class SeataTccOrderServiceImpl implements SeataTccOrderService {
@Override @Override
@Transactional @Transactional
public boolean commitSubmitOrder(BusinessActionContext businessActionContext) { public boolean commitSubmitOrder(BusinessActionContext businessActionContext) {
log.info("==========已经完成Confirm-->创建 订单 第二阶段提交,事务组Xid:{} ==========", businessActionContext.getXid());
if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) { if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) {
log.info("已执行过Confirm阶段");
return true; return true;
} }
IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid()); IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid());
@ -84,21 +85,18 @@ public class SeataTccOrderServiceImpl implements SeataTccOrderService {
@Override @Override
@Transactional @Transactional
public boolean rollbackSubmitOrder(BusinessActionContext businessActionContext) { public boolean rollbackSubmitOrder(BusinessActionContext businessActionContext) {
log.info("======================rollbackSubmitOrder========================");
if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) { if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) {
log.info("已执行过rollback阶段");
return true; return true;
} }
JSONObject jsonObject = (JSONObject) businessActionContext.getActionContext("orderSubmitDTO"); JSONObject jsonObject = (JSONObject) businessActionContext.getActionContext("orderSubmitDTO");
OrderSubmitDTO orderSubmitDTO = new OrderSubmitDTO(); OrderSubmitDTO orderSubmitDTO = new OrderSubmitDTO();
BeanUtil.copyProperties(jsonObject, orderSubmitDTO); BeanUtil.copyProperties(jsonObject, orderSubmitDTO);
OmsOrder omsOrder = orderService.getOne(new LambdaQueryWrapper<OmsOrder>().eq(OmsOrder::getOrderSn, orderSubmitDTO.getOrderToken())); OmsOrder omsOrder = orderMapper.selectOne(new LambdaQueryWrapper<OmsOrder>().eq(OmsOrder::getOrderSn, orderSubmitDTO.getOrderToken()));
if (Objects.nonNull(omsOrder)) { if (Objects.nonNull(omsOrder)) {
orderItemService.remove(new LambdaQueryWrapper<OmsOrderItem>().eq(OmsOrderItem::getOrderId, omsOrder.getId())); orderItemService.remove(new LambdaQueryWrapper<OmsOrderItem>().eq(OmsOrderItem::getOrderId, omsOrder.getId()));
orderService.deleteOrder(omsOrder.getId()); orderMapper.deleteById(omsOrder.getId());
} }
IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid()); IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid());
log.info("========== 已经完成Cancle-->第二阶段回滚,事务组Xid:{} ==========" + businessActionContext.getXid());
return true; return true;
} }
} }

View File

@ -19,6 +19,7 @@ import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock; import org.redisson.api.RLock;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -30,17 +31,17 @@ import static com.youlai.mall.pms.common.constant.PmsConstants.LOCK_SKU_PREFIX;
@Service @Service
@Slf4j @Slf4j
@AllArgsConstructor
public class PmsSkuServiceImpl extends ServiceImpl<PmsSkuMapper, PmsSku> implements IPmsSkuService { public class PmsSkuServiceImpl extends ServiceImpl<PmsSkuMapper, PmsSku> implements IPmsSkuService {
@Autowired
private StringRedisTemplate redisTemplate; private StringRedisTemplate redisTemplate;
@Autowired
private RedissonClient redissonClient; private RedissonClient redissonClient;
@Autowired
private SeataTccSkuService seataTccSkuService; private SeataTccSkuService seataTccSkuService;
@GlobalTransactional
@Override @Override
@GlobalTransactional
public boolean lockStockTcc(List<SkuLockDTO> skuLockList) { public boolean lockStockTcc(List<SkuLockDTO> skuLockList) {
seataTccSkuService.prepareSkuLockList(null,skuLockList); seataTccSkuService.prepareSkuLockList(null,skuLockList);

View File

@ -34,16 +34,13 @@ public class SeataTccSkuServiceImpl implements SeataTccSkuService {
@Autowired @Autowired
private RedissonClient redissonClient; private RedissonClient redissonClient;
@Transactional
@Override @Override
@Transactional
public boolean prepareSkuLockList(BusinessActionContext businessActionContext, List<SkuLockDTO> skuLockList) { public boolean prepareSkuLockList(BusinessActionContext businessActionContext, List<SkuLockDTO> skuLockList) {
log.info("=======================创建订单,开始锁定商品库存=======================");
//防幂等
if (Objects.nonNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) { if (Objects.nonNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) {
log.info("已执行过try阶段");
return true; return true;
} }
log.info("锁定商品信息:{}", skuLockList.toString());
if (CollectionUtil.isEmpty(skuLockList)) { if (CollectionUtil.isEmpty(skuLockList)) {
throw new BizException("锁定的商品列表为空"); throw new BizException("锁定的商品列表为空");
} }
@ -80,9 +77,7 @@ public class SeataTccSkuServiceImpl implements SeataTccSkuService {
@Transactional @Transactional
@Override @Override
public boolean commitSkuLockList(BusinessActionContext businessActionContext) { public boolean commitSkuLockList(BusinessActionContext businessActionContext) {
log.info("=====================commitSkuLockList 成功=========================");
if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) { if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) {
log.info(businessActionContext.getXid() + ": 已执行过commit阶段");
return true; return true;
} }
IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid()); IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid());
@ -92,9 +87,8 @@ public class SeataTccSkuServiceImpl implements SeataTccSkuService {
@Transactional @Transactional
@Override @Override
public boolean rollbackSkuLockList(BusinessActionContext businessActionContext) { public boolean rollbackSkuLockList(BusinessActionContext businessActionContext) {
log.info("======================rollbackSkuLockList========================");
if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) { if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) {
log.info(businessActionContext.getXid() + ": 已执行过rollback阶段");
return true; return true;
} }
JSONArray jsonObjectList = (JSONArray) businessActionContext.getActionContext("skuLockList"); JSONArray jsonObjectList = (JSONArray) businessActionContext.getActionContext("skuLockList");