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 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()0 ? true:false; }
UserAccountMapper.xml中减少账户余额核心的sql
update user_account set account = account - #{cost,jdbcType=BIGINT} where userid = #{userid,jdbcType=BIGINT} AND account > #{cost,jdbcType=BIGINT}
订单微服务Order
pom.xml、application.yml、application-dev.yml、MybatisConfig、主函数相关代码和微服务Goods几乎一样,不在贴代码列举。
application.yml中server.port端口和spring.application.name应用名称根据自己的情况更改,上图是我这边配置。
pom.xml在原来的基础上增加openfeign
org.springframework.cloud spring-cloud-starter-openfeign
因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 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 into `order` orderid, commoditycode, userId, num, money, status, #{orderid,jdbcType=BIGINT}, #{commoditycode,jdbcType=BIGINT}, #{userid,jdbcType=BIGINT}, #{num,jdbcType=BIGINT}, #{money,jdbcType=BIGINT}, #{status,jdbcType=BIGINT},
启动程序
依次启动商品微服务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:2565654285484400642022-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=null2022-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_order2022-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 GlobalFinished2022-04-10 23:39:30.046 INFO 18939 --- [ch_RMROLE_1_2_8] io.seata.rm.AbstractRMHandler : Branch Rollbacked result: PhaseTwo_Rollbacked2022-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=null2022-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_order2022-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 GlobalFinished2022-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
下单成功,返回结果