SpringCloudAlibaba之Seata微服务之间调用(八)

上一节讲述了seata分布式事务设计到的业务表、业务表对应数据库需要seata的表以及商品微服务的代码。本节继续上一节未未完成剩余的两个微服务的描述。

用户账户微服务Account

pom.xml、application.yml、application-dev.yml、MybatisConfig、主函数相关代码和微服务Goods几乎一样,不在贴代码列举。

其中application.yml中server.port端口和spring.application.name应用名称根据自己的情况更改,上图是我这边配置。

新增一个AccountController类,增加一个减少账户余额的请求实现。如下:

@PostMapping("/user/reduceBalance")
    public String balance(@RequestParam("userid") String userid, @RequestParam("cost") String cost) throws Exception {
        boolean isSuccess = accountService.reduceBalance(userid,cost);
        Map<String,String> map= new HashMap<>(8);
        map.put("code",isSuccess?"ok":"fail");
        map.put("msg",isSuccess?"成功":"失败");
        return jsonUtil.objectToJson(map);
    }

accountService的核心代码

public boolean reduceBalance(String userid, String cost) throws Exception {
        logger.info("事务XID:{}", RootContext.getXID());
        UserAccount userAccount = userAccountMapper.selectByPrimaryKey(Long.parseLong(userid));
        if (userAccount.getAccount()<Long.parseLong(cost)){
            throw new Exception("余额不足");
        }
        int row =  userAccountMapper.reduceBalance(userAccount.getUserid(),Long.parseLong(cost));
        return row>0 ? true:false;
    }

UserAccountMapper.xml中减少账户余额核心的sql

<update id="reduceBalance" parameterType="java.lang.Long">
    update user_account
    set account = account - #{cost,jdbcType=BIGINT}
    where userid = #{userid,jdbcType=BIGINT} AND account > #{cost,jdbcType=BIGINT}
  </update>

订单微服务Order

pom.xml、application.yml、application-dev.yml、MybatisConfig、主函数相关代码和微服务Goods几乎一样,不在贴代码列举。

 application.yml中server.port端口和spring.application.name应用名称根据自己的情况更改,上图是我这边配置。

pom.xml在原来的基础上增加openfeign

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

因openfeign内部使用了ribbon实现,默认超时时间为1秒,为了避免超时的情况,更改超时时间。设置为10000毫秒。application.yml中增加配置如下

如果想了解那里设置了默认时间,请查看RibbonClientConfiguration类,如下:

增加AccountFeign接口,调用用户账户相关请求。如下:

@Service
@FeignClient("ACCOUNT")
public interface AccountFeign {
    @PostMapping("/user/reduceBalance")
    public String balance(@RequestParam("userid") String userid, @RequestParam("cost") String cost);
    @GetMapping("/user/{id}")
    public String userAccount(@PathVariable("id") Long id);
}

注意:这里的增加了FeignClient注解,值“ACCOUNT”为用户账户微服务(ACCOUN)中spring.application.name的值。

增加GoodsFeign接口,调用商品相关请求。如下:

@Service
@FeignClient("GOODS")
public interface GoodsFeign {
    @GetMapping("/goods/{id}")
    public String goodsInfo(@PathVariable(value = "id") String id);
    @PostMapping("/goods/deductStorage")
    public String deductStorage(@RequestParam(value="id",defaultValue = "0") String id,@RequestParam(value="count",defaultValue = "0") String count);
}

新增一个OrderController的类,增加创建订单请求代码。如下:

@PostMapping("/order/createOrder")
    public String createOrder(@RequestParam(value="userId",defaultValue = "") String userId,
                              @RequestParam(value="commodityCode",defaultValue = "")String commodityCode,
                              @RequestParam(value="count",defaultValue = "")String count) throws Exception {
        Order order=orderService.saveOrder(userId,commodityCode,count);
        return jsonUtil.objectToJson(order);
    }
OrderService核心代码
@Resource
    OrderMapper orderMapper;
    @Resource
    GoodsFeign goodsFeign;
    @Resource
    AccountFeign accountFeign;
    @GlobalTransactional(name = "createOrder",timeoutMills = 120000,rollbackFor = Exception.class)
    @Override
    public Order saveOrder(String userId, String commodityCode, String count) throws Exception {
        logger.info("------用户下单---------");
        logger.info("事务XID:{}", RootContext.getXID());

        //保存订单
        Order order = new Order();
        order.setUserid(Long.parseLong(userId));
        order.setCommoditycode(Long.parseLong(commodityCode));
        order.setNum(Long.parseLong(count));

        //获取商品信息以及库存信息
        String jsonGoods=goodsFeign.goodsInfo(commodityCode);
        Map<String,Object> map=jsonUtil.jsonToMap(jsonGoods);
        Long price = Long.parseLong(map.getOrDefault("price",0L).toString());
        Long money = price*Long.parseLong(count);
        order.setMoney(money);

        //更新库存信息
        goodsFeign.deductStorage(commodityCode,count);

        //扣减余额
        accountFeign.balance(userId,money.toString());

        //初始化订单状态
        order.setStatus(1L);
        int insertRow = orderMapper.insertSelective(order);
        logger.info("保存订单id:{}{}", order.getOrderid(), insertRow>0?"成功":"失败");
        //int updateRow = orderMapper.updateStatus(Long.parseLong(String.valueOf(insertRow)),1L);
        //logger.info("更新订单id:{} {}",order.getOrderid(),updateRow>0?"成功":"失败");

        return order;
    }

注意,这个使用了GlobalTransactional注解,增加了全局分布式事务,设置timeoutMills超时时间为120秒(因上文设置ribbon的超时时间为10秒,只要所有openfeign不超过这个时间就行),所有的异常都回滚。

OrderMapper.xml中创建订单核心的sql
<insert id="insertSelective" parameterType="com.juwusheng.order.model.Order" >
    insert into `order`
    <trim prefix="(" suffix=")" suffixOverrides="," >
      <if test="orderid != null" >
        orderid,
      </if>
      <if test="commoditycode != null" >
        commoditycode,
      </if>
      <if test="userid != null" >
        userId,
      </if>
      <if test="num != null" >
        num,
      </if>
      <if test="money != null" >
        money,
      </if>
      <if test="status != null" >
        status,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides="," >
      <if test="orderid != null" >
        #{orderid,jdbcType=BIGINT},
      </if>
      <if test="commoditycode != null" >
        #{commoditycode,jdbcType=BIGINT},
      </if>
      <if test="userid != null" >
        #{userid,jdbcType=BIGINT},
      </if>
      <if test="num != null" >
        #{num,jdbcType=BIGINT},
      </if>
      <if test="money != null" >
        #{money,jdbcType=BIGINT},
      </if>
      <if test="status != null" >
        #{status,jdbcType=BIGINT},
      </if>
    </trim>
  </insert>

启动程序

依次启动商品微服务Goods、用户账户微服务Account和订单微服务Order程序。查看nacos服务列表,有4个服务。

 发送post请求http://localhost:7001/order/createOrder?userId=1&commodityCode=1&count=9

userd为1用户只有100块,余额不足,购买失败,订单表数据为空,事务回滚成功。查看日志如下

2022-04-10 23:39:28.024  INFO 18939 --- [nio-7002-exec-2] c.j.goods.service.impl.GoodsServiceImpl  : 事务XID:192.168.0.105:8091:256565428548440064
2022-04-10 23:39:29.757  INFO 18939 --- [ch_RMROLE_1_2_8] i.s.c.r.p.c.RmBranchRollbackProcessor    : rm handle branch rollback process:xid=192.168.0.105:8091:256565428548440064,branchId=256565446432952321,branchType=AT,resourceId=jdbc:mysql://120.25.151.44:3306/seata_order,applicationData=null
2022-04-10 23:39:29.761  INFO 18939 --- [ch_RMROLE_1_2_8] io.seata.rm.AbstractRMHandler            : Branch Rollbacking: 192.168.0.105:8091:256565428548440064 256565446432952321 jdbc:mysql://120.25.151.44:3306/seata_order
2022-04-10 23:39:30.008  INFO 18939 --- [ch_RMROLE_1_2_8] i.s.r.d.undo.AbstractUndoLogManager      : xid 192.168.0.105:8091:256565428548440064 branch 256565446432952321, undo_log deleted with GlobalFinished
2022-04-10 23:39:30.046  INFO 18939 --- [ch_RMROLE_1_2_8] io.seata.rm.AbstractRMHandler            : Branch Rollbacked result: PhaseTwo_Rollbacked
2022-04-10 23:39:30.124  INFO 18939 --- [ch_RMROLE_1_3_8] i.s.c.r.p.c.RmBranchRollbackProcessor    : rm handle branch rollback process:xid=192.168.0.105:8091:256565428548440064,branchId=256565444398714880,branchType=AT,resourceId=jdbc:mysql://120.25.151.44:3306/seata_order,applicationData=null
2022-04-10 23:39:30.124  INFO 18939 --- [ch_RMROLE_1_3_8] io.seata.rm.AbstractRMHandler            : Branch Rollbacking: 192.168.0.105:8091:256565428548440064 256565444398714880 jdbc:mysql://120.25.151.44:3306/seata_order
2022-04-10 23:39:30.207  INFO 18939 --- [ch_RMROLE_1_3_8] i.s.r.d.undo.AbstractUndoLogManager      : xid 192.168.0.105:8091:256565428548440064 branch 256565444398714880, undo_log added with GlobalFinished
2022-04-10 23:39:30.246  INFO 18939 --- [ch_RMROLE_1_3_8] io.seata.rm.AbstractRMHandler            : Branch Rollbacked result: PhaseTwo_Rollbacked

请求参数count改为1时,发送请求

http://localhost:7001/order/createOrder?userId=1&commodityCode=1&count=1

下单成功,返回结果

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值