gulimall-订单服务

P262、商城业务-订单服务-页面环境搭建

在这里插入图片描述
购物车点击“结算”->订单确认页,提交订单->等待支付页面,点击支付->订单支付页面

等待付款页(就是订单详情页): 状态、送货方式、物流信息、收货人信息、配送信息等等

订单页面:用户中心的订单列表页

订单结算页:订单确认页

收银页:支付页面

页面复制到订单服务,所需的静态资源放Nginx
hosts域名修改。Nginx负载均衡路由转发,网关路由。
页面资源路径修改(ctrl+R,替换)
依赖thymeleaf()编写跳转页面Controller类,记得关缓存
订单服务在nacos注册

P263、商城业务-订单服务-整合SpringSession

登录系统登录的用户会放到session里面,session里面的数据其他子域需要同步起来,使用SpringSession实现session共享
导入依赖,session,redis,使用注解EnableRedisHttpSession
设置session是使用redis存储的,配置redis的服务器地址
session的序列化机制是使用Json做的
每个系统都需要一个线程池

页面之间互相跳转编写

P264、商城业务-订单服务-订单基本概念

信息流:商品信息、优惠信息等,数据查询
资金流:付款退款
物流:货物的发送、退货

订单中间枢纽

需求获取多个模块的数据和信息,同时对这些信息进行加工处理后流向下个环节,这一系列就构成了订单的信息流通。

订单构成

父子订单:拆单
在这里插入图片描述
根据上图设计订单表

订单状态

待付款

用户提交订单后,订单进行预下单,目前主流电商网站都会唤起支付,便于用户快速完成支付,需要注意的是待付款状态下可以对库存进行锁定,锁定库存需要配置支付超时时间,超时后将自动取消订单,订单变更关闭状态

已付款/待发货

用户完成订单支付,订单系统需要记录支付时间,支付流水单号便于对账,订单下放到 WMS系统,仓库进行调拨,配货,分拣,出库等操作。

待收货/已发货

仓储将商品出库后,订单进入物流环节,订单系统需要同步物流信息,便于用户实时知悉物品物流状态

已完成

用户确认收货后,订单交易完成。后续支付侧进行结算,如果订单存在问题进入售后状态

已取消

付款之前取消订单。包括超时未付款或用户商户取消订单都会产生这种订单状态。

售后中

用户在付款后申请退款,或商家发货后用户申请退换货。
售后也同样存在各种状态,当发起售后申请后生成售后订单,售后订单状态为待审核,等待商家审核,商家审核通过后订单状态变更为待退货,等待用户将商品寄回,商家收货后订单状态更新为待退款状态,退款到用户原账户后订单状态更新为售后成功。

商品从库存出库以后才真正从库存扣减
退货入库也是真正入库才从库存增加

P265、商城业务-订单服务-订单登录拦截

创建用户登录拦截器(看是否有session)
注意拦截器起作用需要一个Web配置
要共享用户登录数据给其他线程共享

P266、商城业务-订单服务-订单确认页模型抽取

订单确认页
收货人信息:所有收获地址列表
支付方式:货到付款&在线支付(固定方式,页面写死)
送货清单:订单里的所有商品,信息来自购物车,只有价格需要最新价格,而不是之前加到购物车的价格
优惠信息(优惠券、积分查优惠服务)
VO封装数据

P267、商城业务-订单服务-订单确认页数据获取

会员服务查询收获地址列表
订单远程调用
远程查询购物车所有选中的购物项(价格更新为最新价格,商品里新建一个查价格的方法)
用户信息里有积分,不用查,直接取
订单总额
应付价格

P268、商城业务-订单服务-Feign远程调用丢失请求头问题,导致登录状态失效

2种处理,一种传用户id,一种传session,第二种安全
在这里插入图片描述

自动注入:因为添加了注解定义加入了容器中,然后底层就用for和注解反射的方式得到这些拦截器,再通过代理的方式将其赋给spring调用

在这里插入图片描述

P269、商城业务-订单服务-Feign异步调用丢失请求头(上下文)问题

在这里插入图片描述
解决方法
在这里插入图片描述

订单查询上述各种数据使用多线程异步。CompletableFuture

P270、商城业务-订单服务-bug修改

远程返回的数据解码失败
ErrorDecode$Default.decode
改为远程接口不返回BigDecimal price,而是返回R(实际上是购物车模块方法返回缺少ResponseBody)

P271、商城业务-订单服务-订单确认页渲染

前端页面编写,渲染数据

P272、商城业务-订单服务-订单确认页库存查询

和之前的订单确认页数据一起异步查询库存,远程调用库存系统,查询是否有库存

P273、商城业务-订单服务-订单确认页模拟运费效果

根据用户的收获地址计算运费,远程调用会员服务获取收货地址,点击地址发送Ajax请求,编辑前端页面,修改应付总额,第一次进入订单确认页的默认运费

P274、商城业务-订单服务-订单确认页细节显示

运费和地址封装一个VO,地址与运费对应起来
寄送地址,收货人信息都从收获地址处获取

P275、商城业务-订单服务-接口幂等性讨论

订单防重复提交

什么是

接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的

哪些情况

用户多次点击按钮
用户页面回退再次提交
微服务互相调用,由于网络问题,导致请求失败。feign 触发重试机制
其他业务情况

什么情况下需要幂等

以 SQL 为例,有些操作是天然幂等的。

  1. SELECT * FROM table WHER id=?,无论执行多少次都不会改变状态,是天然的幂等。

  2. UPDATE tab1 SET col1=1 WHERE col2=2,无论执行成功多少次状态都是一致的,也是幂等操作。

  3. delete from user where userid=1,多次操作,结果一样,具备幂等性

  4. insert into user(userid,name) values(1,‘a’) 如 userid 为唯一主键,即重复操作上面的业务,只会插入一条用户数据,具备幂等性。

  5. UPDATE tab1 SET col1=col1+1 WHERE col2=2,每次执行的结果都会发生变化,不是幂等的。

  6. insert into user(userid,name) values(1,‘a’) 如 userid 不是主键,可以重复,那上面业务多次操作,数据都会新增多条,不具备幂等性

解决方案

  1. token机制(令牌机制,比如验证码)
    1)先删导致永远进不去,后删导致多次执行
    最好先删除 token,如果业务调用失败,就重新获取 token 再次请求。
    2)但是getToken 判断是否等于token delToken三个操作必须原子性
    可以在 redis 使用 lua 脚本完成这个操作
    if redis.call(‘get’, KEYS[1]) == ARGV[1] then return redis.call(‘del’, KEYS[1]) else return 0 en
  2. 各种锁机制
    1)数据库悲观锁
    select * from xxxx where id = 1 for update
    悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,需要根据实际情况选用。另外要注意的是,id 字段一定是主键或者唯一索引,不然可能造成锁表的结果,处理起来会非常麻烦
    2)数据库乐观锁
    版本号
    3)业务层分布式锁
    比如多台机器定时任务都拿到了相同数据处理,我们就可以加分布式锁,锁定此数据,处理完成后释放锁。获取到锁的必须先判断这个数据是否被处理过。
  3. 各种唯一约束
    1)数据库唯一约束(订单号唯一,防止按照订单号插入数据时不幂等)
    百度秒传给每个文件生成一个MD5值,防重复
    2)redis set 防重
    比如我们可以计算数据的 MD5 将其放入 redis 的 set,每次处理数据,先看这个 MD5 是否已经存在,存在就不处理,相当于Redis的防重表
  4. 防重表
    数据库放一些防重表。使用订单号 orderNo 做为去重表的唯一索引,把唯一索引插入去重表,再进行业务操作,且他们在同一个事务中。
    去重表和业务表应该在同一库中,这样就保证了在同一个事务,即使业务操作失败了,也会把去重表的数据回滚。
  5. 全局请求唯一id
    调用接口时,生成一个唯一 id,redis 将数据保存到集合中(去重),存在即处理过。 feign调用时可以生成一个用来防重
    可以使用 nginx 设置每一个请求的唯一 id;proxy_set_header X-Request-Id $request_id 这个不能做防重
    如果全局id是从页面开始,则可以用来做链路追踪

P276、商城业务-订单服务-订单确认页完成

生成uuid,在页面和服务器(redis set)都保存一份,过期时间30min足够

在这里插入图片描述
刷新页面,令牌就会改
不刷新,连续点2次就是重复提交

订单提交数据(封装VO):
收获地址
支付方式
优惠、发票
防重令牌
备注
应付价格:验价,可做可不做
无需提交需要购买的商品信息,去购物车再查一次,包括实际价格
用户相关信息,直接去session取

前端编写

P277、商城业务-订单服务-原子验令牌

下单功能,成功去支付页,失败返回订单确认页重新确认订单信息
封装下单返回数据,订单实体类,错误状态码

  1. 验证令牌(页面和redis的)
    令牌的对比和删除必须保证原子性
    使用脚本redisTemplate.execute()
    0令牌失败,1删除成功

P278、商城业务-订单服务-构造订单数据

在这里插入图片描述
@事务(整个创建到锁库存)

1、下单,去创建订单,订单项

  1. 订单号
    getTimeId();
  2. 获取收货地址信息
  3. 设置收货人信息
  4. 获取所有订单项

P279、商城业务-订单服务-构造订单项(每个商品)数据

  1. 订单信息(订单号)
  2. 商品spu信息
  3. 商品sku信息(销售属性)
  4. 优惠信息
  5. 积分信息

P280、商城业务-订单服务-订单验价

2、验价

订单总额每一个订单项的总额信息的叠加
应付总额 加运费
积分信息
优惠费用

订单状态设置

P281、商城业务-订单服务-保存订单数据

3、保存订单

订单数据保存到数据库

4、库存锁定(远程调用)。只要有异常,回滚订单数据

创建库存锁定VO

P282、商城业务-订单服务-锁定库存

在这里插入图片描述
@事务
在这里插入图片描述

1、按照下单的收货地址,找到就近仓库,锁定库存
1、找到每个商品在哪个仓库都有库存
2、锁定库存
3、全部都锁定成功

P283、商城业务-订单服务-提交订单的问题

前端页面修改数据

订单创建回滚问题
在这里插入图片描述

P284、商城业务-分布式事务-本地事务在分布式下的问题

本地事务,@Transactional
在这里插入图片描述

P285、商城业务-分布式事务-本地事务隔离级别&传播行为等复习

3、事务的7大传播行为

1、PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,
就加入该事务,该设置是最常用的设置。
2、PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当
前不存在事务,就以非事务执行。
3、PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果
当前不存在事务,就抛出异常。
4、PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
5、PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当
前事务挂起。
6、PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
7、PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,
则执行与 PROPAGATION_REQUIRED
在这里插入图片描述
在这里插入图片描述

P286、商城业务-分布式事务-分布式CAP&Raft原理

在这里插入图片描述
在这里插入图片描述
CAP原理:

  1. 一致性(Consistency):
    在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)
  2. 可用性(Availability)
    在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)
  3. 分区容错性(Partition tolerance)
    大多数分布式系统都分布在多个子网络。每个子网络就叫做一个区(partition)。分区容错的意思是,区间通信可能失败。比如,一台服务器放在中国,另一台服务器放在美国,这就是两个区,它们之间可能无法通信。
  4. CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。1和2满足其一,3必须满足

raft算法
raft是一种协议
任何节点有3状态,leader(领导),follower(跟随),candidate(候选)
机制:
领导选举:必须选出一个唯一的leader,不然要一直投票
日志复制:在心跳时间的时候发送

类似redis的哨兵

P287、商城业务-分布式事务-BASE

节点故障、网络故障是常态,而且要保证服务可用性达到 99.99999%(N 个 9),即保证P 和 A,舍弃 C。

CAP的一致性就是强一致性

对于关系型数据库,要求更新过的数据能被后续的访问都能看到,这是强一致性。如果能容忍后续的部分或者全部访问不到,则是弱一致性。如果经过一段时间后要求能访问到更新后的数据,则是最终一致性

BASE理论:
是对 CAP 理论的延伸,思想是即使无法做到强一致性(CAP 的一致性就是强一致性),但可以采用适当的采取弱一致性,即最终一致性。
BASE 是指

  1. 基本可用(Basically Available)
  2. 软状态( Soft State)
  3. 最终一致性( Eventual Consistency)

P288、商城业务-分布式事务-分布式事务常见解决方案

2PC(二阶提交)模式(刚性事务)

在这里插入图片描述

柔性事务-TCC事务补偿型方案

刚性事务:遵循 ACID 原则,强一致性。
柔性事务:遵循 BASE 理论,最终一致性;
与刚性事务不同,柔性事务允许一定时间内,不同节点的数据不一致,但要求最终一致。

柔性事务-最大努力通知型方案

不保证数据一定能通知成功,但会提供可查询操作接口进行核对。

柔性事务-可靠消息+最终一致性方案(异步确保型)

P289、商城业务-分布式事务-Seata&环境准备

Seata是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。提供了AT、TCC、SAGA和XA事务模式

P290、商城业务-分布式事务-Seata分布式事务体验

P291、商城业务-分布式事务-最终一致性库存解锁逻辑

延时队列

P292、商城业务-订单服务-RabbitMQ延时队列

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
实现2有个弊端,发送3个消息,过期时间分别为5min,1min,1s,服务器得等第一个5min的过期并扔给死信路由才会检查第二个。

P293、商城业务-订单服务-延时队列定时关单模拟

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

P294、商城业务-订单服务-创建业务交换机&队列

在这里插入图片描述
在这里插入图片描述
交换机都是Bean
订单有自动解锁功能

P295、商城业务-订单服务-监听库存解锁

在这里插入图片描述
库存锁定成功。
保存库存工作单(某个订单锁库存)和库存工作单详情(哪个商品锁了几个库存在哪仓库锁的和锁定状态1-锁定2-解锁3-扣减),用来追溯。
就发消息给MQ,触发自动解锁功能

下单远程锁定库存,然后将仓库锁定库存的数据发给订单,当在订单下单失败时,由于不是分布式事务,订单回滚,但仓库不回滚,所以订单一失败,就需要通过订单拿到mq中仓库传来的数据通知仓库解锁库存

P296、商城业务-订单服务-库存解锁逻辑

在这里插入图片描述
rabbitMQ一般使用手段ACK模式

P296、商城业务-订单服务-库存自动解锁完成

订单远程服务查询订单状态报数据类型转换异常,html转不了R对象
原因:被登录拦截给拦截了,设置放行
使用new AntPathMatcher().match(“放行路径”,目标路径)

P297、商城业务-订单服务-测试库存自动解锁

ACK机制是消费者从RabbitMQ收到消息并处理完成后,反馈给RabbitMQ,RabbitMQ收到反馈后才将此消息从队列中删除。
如果一个消费者在处理消息出现了网络不稳定、服务器异常等现象,那么就不会有ACK反馈,RabbitMQ会认为这个消息没有正常消费,会将消息重新放入队列中。

P298、商城业务-订单服务-定时关单完成

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

所以订单解锁后要发消息到交换机再到解锁库存服务监听的消息队列(库存解锁队列)

下订单后, 如果超时没支付, 直接取消订单, 同时取消锁定库存, 并且下单的时候同时下一条延迟解锁库存的消息给MQ , 过一段固定时间检查

提交订单,订单表多一个状态新建的订单,锁定库存+1。超时后,订单关闭,状态变为4,库存解锁(不是自动解锁,而是订单关闭,给他发消息),收到MQ中库存自动解锁消息,发现已解锁,就跳过,不重复解锁

P299、商城业务-订单服务-消息丢失、积压、重复等解决方案

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ack自动:消费者一拿到消息就给MQ会服消息,不保证消费成功
ack手动:消费者消费成功才给MQ发消息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值