博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用SpringCloud Alibaba搭建属于自己的微服务(三十八)~业务开发~下订单核心接口加入seata做分布式事务
阅读量:4204 次
发布时间:2019-05-26

本文共 10016 字,大约阅读时间需要 33 分钟。

一.概述

我们这个ccm-mall工程,核心接口就是下订单接口,在之前的章节已经讲解过,该接口涉及了四个微服务server-user、server-goods、server-pay和server-order.本章节我们将该接口加入seata分布式事务,保证在异常情况下的数据一致性.

二.server-user、server-goods、server-pay和server-order集成seata.

1.server-user、server-goods、server-pay和server-order的pom中加入相关依赖.

com.alibaba.cloud
spring-cloud-alibaba-seata
2.2.0.RELEASE
io.seata
seata-spring-boot-starter
io.seata
seata-spring-boot-starter
1.2.0

2.server-user、server-goods、server-pay和server-order的bootstrap.yml中加入相关配置.

seata:  enabled: true  application-id: ${
spring.application.name} tx-service-group: my_test_tx_group enable-auto-data-source-proxy: true config: type: nacos nacos: namespace: serverAddr: 47.96.131.185:8849 group: SEATA_GROUP userName: "nacos" password: "nacos" registry: type: nacos nacos: application: seata-server #seata服务端(TC)在nacos中的应用名称 server-addr: 47.96.131.185:8849 namespace: userName: "nacos" password: "nacos"

3.user、pay、goods和order数据库加入表undo_log.

在这里插入图片描述在这里插入图片描述

在这里插入图片描述在这里插入图片描述

undo_log表sql脚本的位置:seata资源包路径:seata-1.2.0/script/client/at/db/mysql.sql

三.代码改造

1.下订单核心接口加入@GlobalTransactional注解,代表开启seata分布式事务管理

package com.ccm.server.order.service.impl;import com.alibaba.nacos.client.naming.utils.CollectionUtils;import com.ccm.common.exception.CustomerException;import com.ccm.common.exception.result.ResultSet;import com.ccm.server.order.config.OrderIdGenerator;import com.ccm.server.order.controller.req.PayOrderReq;import com.ccm.server.order.dao.mysql.domain.OrderInfo;import com.ccm.server.order.dao.mysql.domain.OrderSku;import com.ccm.server.order.dao.mysql.mapper.OrderInfoMapper;import com.ccm.server.order.dao.mysql.mapper.OrderSkuMapper;import com.ccm.server.order.feign.ServerGoodsFeign;import com.ccm.server.order.feign.ServerPayFeign;import com.ccm.server.order.feign.req.ReduceStockReq;import com.ccm.server.order.feign.vo.GoodsSkuVO;import com.ccm.server.order.service.OrderService;import io.seata.spring.annotation.GlobalTransactional;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.util.ArrayList;import java.util.List;import java.util.stream.Collectors;/** *  @Description 订单业务层实现类 *  @Author ccm *  @CreateTime 2020/08/14 10:11 */@Servicepublic class OrderServiceImpl implements OrderService {
@Autowired private OrderSkuMapper orderSkuMapper; @Autowired private OrderInfoMapper orderInfoMapper; @Autowired private ServerGoodsFeign serverGoodsFeign; @Autowired private OrderIdGenerator orderIdGenerator; @Autowired private ServerPayFeign serverPayFeign; @Override @GlobalTransactional @Transactional(rollbackFor = Exception.class) public void order(List
payOrderReqList, Long userId) {
//生成订单号 String orderId = orderIdGenerator.nextOrderId(); //获取商品的详细信息 ResultSet
> resultSet = serverGoodsFeign.selectByIdList(payOrderReqList.stream() .map(PayOrderReq::getSkuId) .collect(Collectors.toList())); List
goodsSkuVOList = ResultSet.getFeignData(resultSet); if(CollectionUtils.isEmpty(goodsSkuVOList) || goodsSkuVOList.size()!=payOrderReqList.size()) {
throw new CustomerException("商品不存在"); } //扣商品库存 List
reduceStockReqList = payOrderReqList.stream() .map(t -> new ReduceStockReq(t.getSkuId(),t.getSkuNumber())) .collect(Collectors.toList()); ResultSet.getFeignData(serverGoodsFeign.reduceStock(reduceStockReqList)); //支付 BigDecimal totalMoney = new BigDecimal(0.0d); for(PayOrderReq payOrderReq:payOrderReqList) {
for(GoodsSkuVO goodsSkuVO:goodsSkuVOList) {
if(payOrderReq.getSkuId().equals(goodsSkuVO.getId())) {
BigDecimal skuNumber = new BigDecimal(payOrderReq.getSkuNumber()); totalMoney = totalMoney.add(goodsSkuVO.getPrice().multiply(skuNumber)); break; } } } String flowingWaterId = ResultSet.getFeignData(serverPayFeign.pay(userId, totalMoney)); //主订单表插入数据 OrderInfo orderInfo = new OrderInfo(); orderInfo.setId(orderId); orderInfo.setAmountMoney(totalMoney); orderInfo.setStatus(1); orderInfo.setUserId(userId); orderInfo.setFlowingWaterId(flowingWaterId); orderInfoMapper.insert(orderInfo); //子订单表插入数据 ArrayList
orderSkuList = new ArrayList<>(); payOrderReqList.forEach(payOrderReq -> { OrderSku orderSku = new OrderSku(); orderSku.setOrderId(orderId); orderSku.setSkuNumber(payOrderReq.getSkuNumber()); orderSku.setSkuId(payOrderReq.getSkuId()); for(GoodsSkuVO goodsSkuVO:goodsSkuVOList) { if(payOrderReq.getSkuId().equals(goodsSkuVO.getId())) { orderSku.setSkuMoney(goodsSkuVO.getPrice()); break; } } orderSkuList.add(orderSku); }); orderSkuMapper.insertList(orderSkuList); }}

四.模拟下单成功的情况

1.数据库原始数据准备

(1).user.user_info表为ccm账户充值到10万元

在这里插入图片描述

(2).goods.goods_sku商品表加入两个商品,库存都为10

在这里插入图片描述

2.启动gateway、server-user、server-goods、server-pay和server-order服务

在这里插入图片描述

3.打开gateway的swagger界面

在这里插入图片描述

4.接口测试

购买一台苹果11和两台华为P30

在这里插入图片描述

在这里插入图片描述

5.查看测试结果

(1).账户被扣除

在这里插入图片描述

(2).生成了支付流水

在这里插入图片描述

(3).生成了主订单和子订单

在这里插入图片描述在这里插入图片描述

(4).商品库存被扣除

在这里插入图片描述

五.模拟下单失败的情况

1.订单接口逻辑最后加入 int i = 1/0模拟下单出现异常.

package com.ccm.server.order.service.impl;import com.alibaba.nacos.client.naming.utils.CollectionUtils;import com.ccm.common.exception.CustomerException;import com.ccm.common.exception.result.ResultSet;import com.ccm.server.order.config.OrderIdGenerator;import com.ccm.server.order.controller.req.PayOrderReq;import com.ccm.server.order.dao.mysql.domain.OrderInfo;import com.ccm.server.order.dao.mysql.domain.OrderSku;import com.ccm.server.order.dao.mysql.mapper.OrderInfoMapper;import com.ccm.server.order.dao.mysql.mapper.OrderSkuMapper;import com.ccm.server.order.feign.ServerGoodsFeign;import com.ccm.server.order.feign.ServerPayFeign;import com.ccm.server.order.feign.req.ReduceStockReq;import com.ccm.server.order.feign.vo.GoodsSkuVO;import com.ccm.server.order.service.OrderService;import io.seata.spring.annotation.GlobalTransactional;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.util.ArrayList;import java.util.List;import java.util.stream.Collectors;/** *  @Description 订单业务层实现类 *  @Author ccm *  @CreateTime 2020/08/14 10:11 */@Servicepublic class OrderServiceImpl implements OrderService {
@Autowired private OrderSkuMapper orderSkuMapper; @Autowired private OrderInfoMapper orderInfoMapper; @Autowired private ServerGoodsFeign serverGoodsFeign; @Autowired private OrderIdGenerator orderIdGenerator; @Autowired private ServerPayFeign serverPayFeign; @Override @GlobalTransactional @Transactional(rollbackFor = Exception.class) public void order(List
payOrderReqList, Long userId) {
//生成订单号 String orderId = orderIdGenerator.nextOrderId(); //获取商品的详细信息 ResultSet
> resultSet = serverGoodsFeign.selectByIdList(payOrderReqList.stream() .map(PayOrderReq::getSkuId) .collect(Collectors.toList())); List
goodsSkuVOList = ResultSet.getFeignData(resultSet); if(CollectionUtils.isEmpty(goodsSkuVOList) || goodsSkuVOList.size()!=payOrderReqList.size()) {
throw new CustomerException("商品不存在"); } //扣商品库存 List
reduceStockReqList = payOrderReqList.stream() .map(t -> new ReduceStockReq(t.getSkuId(),t.getSkuNumber())) .collect(Collectors.toList()); ResultSet.getFeignData(serverGoodsFeign.reduceStock(reduceStockReqList)); //支付 BigDecimal totalMoney = new BigDecimal(0.0d); for(PayOrderReq payOrderReq:payOrderReqList) {
for(GoodsSkuVO goodsSkuVO:goodsSkuVOList) {
if(payOrderReq.getSkuId().equals(goodsSkuVO.getId())) {
BigDecimal skuNumber = new BigDecimal(payOrderReq.getSkuNumber()); totalMoney = totalMoney.add(goodsSkuVO.getPrice().multiply(skuNumber)); break; } } } String flowingWaterId = ResultSet.getFeignData(serverPayFeign.pay(userId, totalMoney)); //主订单表插入数据 OrderInfo orderInfo = new OrderInfo(); orderInfo.setId(orderId); orderInfo.setAmountMoney(totalMoney); orderInfo.setStatus(1); orderInfo.setUserId(userId); orderInfo.setFlowingWaterId(flowingWaterId); orderInfoMapper.insert(orderInfo); //子订单表插入数据 ArrayList
orderSkuList = new ArrayList<>(); payOrderReqList.forEach(payOrderReq -> { OrderSku orderSku = new OrderSku(); orderSku.setOrderId(orderId); orderSku.setSkuNumber(payOrderReq.getSkuNumber()); orderSku.setSkuId(payOrderReq.getSkuId()); for(GoodsSkuVO goodsSkuVO:goodsSkuVOList) { if(payOrderReq.getSkuId().equals(goodsSkuVO.getId())) { orderSku.setSkuMoney(goodsSkuVO.getPrice()); break; } } orderSkuList.add(orderSku); }); orderSkuMapper.insertList(orderSkuList); int i = 1/0; }}

2.数据库原始数据准备

(1).user.user_info表为ccm账户充值到10万元

在这里插入图片描述

(2).goods.goods_sku商品表加入两个商品,库存都为10

在这里插入图片描述

2.启动gateway、server-user、server-goods、server-pay和server-order服务

在这里插入图片描述

3.打开gateway的swagger界面

在这里插入图片描述

4.接口测试

购买一台苹果11和两台华为P30

在这里插入图片描述

在这里插入图片描述

5.查看测试结果

(1).账户余额没有被扣除

在这里插入图片描述

(2).没有生成支付流水

在这里插入图片描述

(3).没有生成主订单和子订单

在这里插入图片描述

在这里插入图片描述

(4).商品没有被扣除库存

在这里插入图片描述

以上证明,下单失败时,所有数据都回滚了,保证了在分布式的情况下的数据的一致性!

您的点赞、收藏、转发和关注是我持续创作的动力!

源码地址:

转载地址:http://butli.baihongyu.com/

你可能感兴趣的文章