宠宝购物购物车+订单

MQ

1.为什么要使用MQ? MQ的优点?

  • 为了解藕,系统跟系统传递消息间是耦合,使用 MQ,A 系统产生一条数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。
  • 为了异步,减少请求与响应的耗时,给用户更好的体验感
  • 削峰:减少高峰时期对服务器压力。
  • 日志处理 - 解决大量日志传输。
  • 消息通讯 - 消息队列一般都内置了高效的通信机制

2.MQ的优点

1.解藕 2.异步 3.削峰

缺点:考虑一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等

3.如何消息的顺序问题

保证生产者 - MQServer - 消费者是一对一对一的关系,假如有两个消费者1,2,消费1消费完后通知MQServer,再发送给消费2,

缺陷:

并行度成问题,会有更多的异常处理

3.MQ怎么解决消息的重复消费问题

1.MQ出现重复消费的场景
	1)提供者给MQ发送消息
	2)消费者1拉取这个消息(消息状态为待应答)
	3)消费者1把这个消息转成数据库的一条记录
	4)手动ack(网络出现故障,消费者和MQServer断开,断开后channel也就关闭了,消息状态变为待分配)
	5)MQServer接着把这个消息,发送给消费者2,消费者2接着消费就是重复消费
2.消息确认机制(Acknowlege)。当消费者获取消息后,会向RabbitMQ发送回执ACK,告知消息已经被接收。
	自动ACK:消息一旦被接收,消费者自动发送ACK
	手动ACK:消息接收后,不会发送ACK,需要手动调用,RabbitMQ就会把消息从队列中删除。
3.如何解决重复消费的问题
	1)给每个消息分配的一个全局的id,记录这个消息的消费状态
	2)消费者拿到这个消息后先判断这和消息是否已经被消费过
	3)消费完成后把这个消息的状态记录在redis中

4.RabbitMQ中有哪些组件?

1.MQServer
2.VirtualHost:虚拟主机
3.Exchange
4.Queue
5.Routing:路由器
6.Channel:信道(信道断开后,待应答的消息全部变成待分配)
7.Binding :路由和交换机的绑定

5.RabbitMQ的工作模式

1.简单模式
a)一个提供者,一个队列,一个消费者
b)一个发送消费,一个消费信息
2.工作模式
a)一个提供这个,一个队列,两个消费者
b)加快MQ消费速度
3.发布订阅
a)一个提供这个,一个交换机,一个队列,两个消费者
b)交换机把消息广播给所有的队列,每个队列都有一个消费者

4.路由键
a)一个提供这个,一个交换机,一个路由键,两个队列,两个消费者

5.主题模式
a)一个提供这个,一个交换机,一个路由键,两个队列,两个消费者
b) 关键词 : * :匹配一个  #: 匹配多个

6.如何保证RabbitMQ消息的可靠传输?

生产者丢失消息:开启事务,然后发送消息,如果发送过程中出现什么异常,事务就会回滚

消息队列丢数据:消息持久化

  1. 将queue的持久化标识durable设置为true,则代表是一个持久的队列
  2. 发送消息的时候将deliveryMode=2

消费者丢失消息:消费者丢数据一般是因为采用了自动确认消息模式,改为手动确认消息即可

cookie

本质是一小段的文本信息,格式的字典,key=value

会话cookie:保存在内存中,当浏览器的会话关闭时自动消失

持久cookie: 保存在硬盘中,只有失效时间到了,会自动消失

格式:(name,value值,Domain:域名,Path:路径,expries 失效时间)

cookie传输原理:

1.客户端第一次请求是,服务器产生cookie,通过响应头里面的set-Cookie把cookie传给客户端

2.当客户端第二次请求一直到后面的所有请求,在请求头的Cookie都会带上以上的Cookie信息,从而实现鉴权

Session

保存一些重要信息数据在服务器,通过cookie传给客户端,生命周期默认30分钟

Session鉴权原理

当客户端第一次登陆服务器时,服务器就会产生session, 还有sessionId, cookie响应给客户端时,会携带此次创建session的sessionId,用户再请求时,通过比对sessionId,就知道用户是否有访问权限

Token

1.登录之后自动生成

2.通过一个特定的获取token的接口获取token,通过appid和secret

然后后面的每一次请求都必须带上token实现鉴权,

加密方式: MD5,SHA系列 BCryptPasswordEncoder密码加密对象

access_token: 时效15分钟-2小时

refresh——token:时效15天

cookie与session与token 相同点与区别:

相同点: 都用于身份验证鉴权,都是服务器产生

q区别:

1.cookie保存在客户端,seesion存贮在服务器

2.session保存在服务器,生命周期默认30分钟

3.token是保存在服务器的数据库里面,持久
在这里插入图片描述

将对象转换为json
        //2.将对象转换为json
        //Gson-->toJson  (需要自己找依赖)
        //fastjson-->JSON (spring-cloud-starter-alibaba-sentinel)
        //jackson-->writeValueAsString (spring-boot-starter-web)
        String jsonStr=new ObjectMapper().writeValueAsString(object);

JWT令牌

JWT是用于微服务之间传递用户信息的一段加密字符串,该字符串是一个JSON格式,各个微服务可以根据JWT识别用户身份信息,保存用户信息到客户端,JWT令牌生成采用非对称加密算法

JWT令牌由三部分组成

Header头部: 令牌的类型(即JWT)及使用的签名算法 , 加密方式:Base64,可解密

Payload负载:1.标准中的注册声明 2.公共的声明(不参与令牌校验)3.私有声明(不参与令牌校验)

​ 加密方式:Base64,可解密

Signature签名 : header (base64后的)+payload (base64后的)+secret(秘钥)->加密:采用头部指定算法进行加密->密文->签名

鉴权的主要作用在签名中,网关中会有secret(秘钥)与传输来JWT中的Header和Payload加密,再与签名比对,以此判断jwt是否被篡改

用于防止jwt内容被篡改

项目中用户登录令牌的实现流程

  1. 用Bcrypassword.checkpw方法,判断用户的密码与数据库的是否一致
  2. 创建用户令牌信息用HashMap封装 生成的Jwt令牌Jwts.builder()
  3. 把Jwt令牌封装在cookie中,添加response中
  4. 返回登录成功的RESULT 和 token
    在这里插入图片描述

实现流程:

​ 1.Spring以封装好,sca-auth认证授权服务,添加Oauth2 依赖,启动时,会返回一个默认的密码

​ 2.修改SecurityConfig配置类,添加登录成功或失败的处理逻辑,

​ 3.实现 UserDetailsService 获取用户详细信息的接口,用来与数据库中的用户信息作对比,认证是否正确,可否授权

在这里插入图片描述

​ 4.网关的配置中 Path=/auth/login/ 设置请求路径设计

	5. 构建令牌配置对象,JWT(Json Web Token-是一种json格式)方式将用户信息转换为json格式,然后进行加密,保存用户信息到客户端,客户端接收到这个JWT之后,保存在客户端,之后带着JWT访问其它模块时,资源服务器解析获得用户信息,进行访问,达到解放内存的目的
	6.  资源服务器配置,因为在认证授权服务器中已生成令牌token,此时,用户已携带此token来访问资源服务器, 资源服务器,要校验用户的token,是否合法,是否有效,所以在资源服务器中需要增加令牌配置
	7. 在ResourceController的上传方法上添加 @PreAuthorize(“hasAuthority(‘sys:res:create’)”)注解,用于告诉底层框架方法此方法需要具备的权限

在这里插入图片描述

Nginx

实现负载均衡,占有内存少不超过2M,并发能力强 5万/秒并发能力 实测: 2-3万/秒

反向代理

\1. 用户向代理服务器发送请求,(以为代理服务器就是真实目标服务器)
\2. 代理服务器接收请求时,根据自己的映射文件,重新发起新的请求 访问真实的目标服务器.
\3. 根据映射路径,查找真实的服务器资源.
\4. 获取资源返回给代理服务器.
\5. 代理服务器将资源交换给用户.

限流

漏桶算法

1.控制速率 2.控制并发数量

nginx.conf 限流配置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

网关

作用

  • 安全,提供了统一的访问入口,降低了服务器受攻击面积
  • 提供了统一跨域解决方案
  • 提供了统一日志记录操作,可以进行统一监控
  • 提供统一的权限认证支持(校验token)
  • 提供了微服务限流功能,可以保护微服务,防止雪崩效应发生
  • 最主要作用整合各个微服务功能,形成一套或者多套系统

在这里插入图片描述

Nginx (tengine x) 是一个高性能的HTTP反向代理web服务器,最外层流量拦截,抗高并发,耗时少,稳定,默认端口80

spring-cloud-gateway, 是spring 出品的 基于spring 的网关项目,集成断路器,路径重写,性能比Zuul好。

微服务网关做路由功能,整合各大微服务形成一套系统

spring:
  application:
    name: sca-gateway
  cloud:
    gateway:
    	globalcors:  #全局配置
        cors-configurations:
          '[/**]': # 匹配所有请求
              allowedOrigins: "*" #跨域处理 允许所有的域
              allowedMethods: # 支持的方法
                - GET
                - POST
                - PUT
                - DELETE
         
        routes: #配置网关路由规则 ,可接下来配置与其他微服务的路由规则,哪些路径转发到哪些微服务
          - id: route01  #路由id,自己指定一个唯一值即可
            #uri: http://localhost:8081/ 		#网关帮我们转发的url
            uri: lb://sca-provider # lb为服务前缀(负载均衡loadbalance单词的缩写) +微服务名称
            predicates: ###断言(谓此):匹配请求规则
              - Path=/nacos/provider/echo/**  #请求路径定义,此路径对应uri中的资源
            filters: ##网关过滤器,用于对谓词中的内容进行判断分析以及处理
              - StripPrefix=1 #转发之前去掉path中第一层路径,例如nacos
              #- PrefixPath=/brand #转发之前加上path中第一层路径 /brand
logging: #日志打开到debug
  level:
    org.springframework.cloud.gateway: debug	

网关负载均衡

网关是所有微服务访问的入口,并发量较大的时候,我们需要根据服务server Id的名称判断来做负载均衡操作。

如果Gateway Handler Mapping 通过断言predicates(predicates)的集合确定请求与路由(Routers)匹配,则将其发送到Gateway Web Handler。 Gateway Web Handler 通过确定的路由中所配置的过滤器集合链式调用过滤器,通过底层调用Ribbon 使用 服务名 去查找具体的服务实例

在这里插入图片描述

网关限流

项目中,有两层网关,第一层是nginx,主要是针对大量请求,流量的抵御,这时候它所释放的到微服务网关的流量是比较大的,第二层通过网关做限流,控制到每个微服务的流量,可以对每个服务起到保护的作用

限流算法

令牌算法 :1.匀速生成令牌存入到令牌桶中->Redis 5/s

在这里插入图片描述

漏桶算法:nginx运用

计数算法:

项目中 spring cloud gateway 默认使用redis的RateLimter限流算法来实现,定义KeyResolver用于计算某一个类型的限流的KEY也就是说,可以通过KeyResolver来指定限流的Key。

我们可以根据IP来限流,每个IP每秒钟只能请求一次

Sentienl

还可以结合Sentinel限流,

1.添加依赖,alibaba-sentinel 、alibaba-sentinel-gateway

2.添加配置

sentinel:
  transport:
    dashboard: localhost:8180 #Sentinel 控制台地址
    port: 8719 #客户端监控API的端口
  eager: true  #取消Sentinel控制台懒加载,即项目启动即连接

3.其限流的类型有几种?(两种-route id,api)

4.Sentinel底层限流的算法有哪些?(滑动窗口,令牌桶,漏斗

5.限流:系统能够承受的访问量进来,超出的会被丢弃。限流则从用户访问压力的角度来考虑如何应对故障

​ 熔断:比如A服务的X功能依赖B服务的某个接口,当B服务接口响应很慢时,A服务X功能的响应也会被拖慢,即A服务不在请求B这个接口,A服务内部发现B接口就直接返回错误,熔断的目的是应对外部系统的故障。

​ 降级:系统将某些不重要的业务或接口的功能降低,可以提供核心主业务服务功能,降级是应对系统自身的故障

Feign

调用步骤

1.添加了 Spring Cloud OpenFeign 的依赖
2.在 SpringBoot 启动类上添加了注解 @EnableFeignCleints
3.按照 Feign 的规则定义接口 DemoService, 添加@FeignClient 注解
4.在需要使用 Feign 接口 DemoService 的地方, 直接利用@Autowire 进行注入
5.使用接口完成对服务端的调用

工作原理:

1.SpringBoot 应用启动时, 由针对 @EnableFeignClient 触发程序扫描 classPath中所有被@FeignClient 注解的类, 由系统底层创建DemoService接口实现类(JDK代理类,虚假的实现类代理),并构建类的对象,然后交给spring管理

2.当对DemoService接口实现类调用时,都被转交给 Feign 框架, 翻译成 HTTP 的形式发送出去, 并得到返回结果, 再翻译回接口定义的返回值形式。

项目介绍

1.宠宝购物商城是基于springboot框架和springcloud组件开发的一款B2C电商模式

2.运营商把自家的产品发布到网站上,用户注册登录便可选购宠物相关的产品

3.主要由用户管理系统、商品系统、订单系统、广告系统、秒杀系统、支付系统、购物车系统、后台管理系统组成。

4.系统登录使用jwt令牌的单点登录系统,支持spring Oauth2.0协议,部分服务系统需验证用户携带token,及权限,提供相应的服务

采用MYSQL做持久化存储,REDIS做分布式锁保证订单与库存,使用分布式事务Seata AT模式控制各服务间数据一致性

登录

采用了BCryptPasswordEncoder进行加密,需要将资料中的BCrypt导入到common工程中,其中BCrypt.checkpw(“明文”,“密文”)用于对比密码是否一致。

JWT令牌

JWT是用于微服务之间传递用户信息的一段JSON格式的加密字符串,各个微服务可以根据JWT识别用户身份信息,保存用户信息到客户端,JWT令牌生成采用非对称加密算法

JWT令牌由三部分组成

Header头部: 令牌的类型(即JWT)及使用的签名算法 , 加密方式:Base64,可解密

Payload负载:1.标准中的注册声明 (颁发令牌的信息,签发者,过期时间等等)2.公共的声明(不参与令牌校验)3.私有声明(不参与令牌校验)

​ 加密方式:1.+2.+3. 进行 Base64加密, 可解密

Signature签名 : header (base64后的)+payload (base64后的)+secret(秘钥)->加密:采用头部指定算法进行加密->密文->签名

鉴权的主要作用在签名中,网关中会有secret(秘钥)与传输来JWT中的Header和Payload加密,再与签名比对,以此判断jwt是否被篡改

用于防止jwt内容被篡改

项目中用户登录令牌的实现流程

  1. 用Bcrypassword.checkpw方法,判断用户的密码与数据库的是否一致
  2. 创建用户令牌信息用HashMap封装 生成的Jwt令牌Jwts.builder()
  3. 把Jwt令牌封装在cookie中,添加response中
  4. 返回登录成功的RESULT 和 token

网关鉴权

定义全局过滤器,接收请求request中获取 到令牌的值并解析,解析成功说明令牌有效,方便后面其他服务先把从cookie中的token挪到 请求头 再可放行

单点登录-Spring security Oauth2

用户在其中任何一个站点登录后,可以免登录访问其他所有站点。

Spring Security 是什么?(spring框架中的一个安全默认,实现了认证和授权操作)

OAUTH协议

最主要是解决认证协议的通用标准问题,因为要实现跨系统认证,各系统之间要遵循一定的
接口协议。

oauth2定义了一种认证授权协议,一种规范,此规范中定义了四种类型的角色:

1)资源拥有者(User)
2)认证授权服务器(jt-auth)
3)资源服务器(jt-resource)
4)客户端应用(jt-ui)
同时,在这种协议中规定了认证授权时的几种模式:
1)密码模式 (基于用户名和密码进行认证)
2)授权码模式(就是我们说的三方认证:QQ,微信,微博,。。。。)
3)隐式授权模式(Implicit)
4)客户端模式(Client Credentials)

在这里插入图片描述

1、用户请求认证服务完成认证。

2、认证服务下发用户身份令牌,拥有身份令牌表示身份合法。

3、用户携带令牌请求资源服务,请求资源服务必先经过网关。

4、网关校验用户身份令牌的合法,不合法表示用户没有登录,如果合法则放行继续访问。

5、资源服务获取令牌,根据令牌完成授权。

6、资源服务完成授权则响应资源信息。

公钥私钥

非对称加密算法RSA生成的, 公钥加密(各个服务可以校验私钥信息),私钥解密(授权服务)

Keytool 是一个java提供的证书管理工具 ,每个证书包含公钥和私钥 ,openssl是一个加解密工具包(要下载)

1.在一个文件下cmd执行Keytool 命令生成changgou.jks证书-> 2.在changgou.jks所在目录执行指令导出公钥->3.公钥拷贝到文本public.key文件中,合并为一行->4.将它放到需要实现授权认证的工程

根据私钥生成jwt令牌

根据创建证书路径,创建秘钥工厂,获取私钥—>定义Payload,生成Jwt令牌

根据公钥解析令牌

提供令牌,对公钥RSA算法的对象 给 JwtHelper来解析校验
在这里插入图片描述

项目中在定义全局过滤器中判断token有效,鉴权

  1. 获取用户令牌信息 (1)头文件(2)参数(3)cookie
  2. 如果没令牌,则拦截,如果有,检验是否有效(解析token,前缀是否有bearer,没有帮加上),无效也拦截
  3. 将令牌封装到头文件中,方便为检验用户spring Oauthor2.0 是否有授权认证
  4. 有效放行chain.filter()
    在这里插入图片描述

商品表结构介绍

sku

同款商品所独有属性字段

在这里插入图片描述

spu

同款商品所共有的属性的抽取

购物车

只是目前临时存储数据到Redis,等用户下单后才将数据从Redis取出存入到MySQL中。

先校验用户的权限,并校验令牌

登录认证

资源服务器授权配置

1.将公钥拷贝到 public.key文件中,将此文件拷贝到每一个需要的资源服务工程的classpath下

2.添加依赖 spring-cloud-starter-oauth2

3.写一个配置类,配置此系统的Http请求路径安全控制策略(就是哪些路径需要校验,哪些路径可以跳过校验像注册)以及读取公钥信息识别令牌

@Configuration // 配置类

@EnableResourceServer //开启资源服务器校验->令牌校验

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)

//激活方法上的@PreAuthorize注解

以上配置完后,必须携带有效token访问此资源服务器

访问认证服务器中,UserDetailsServiceImpl中会查询数据库核实用户的身份信息,及所拥有权限

在资源服务器的具体执行方法上定义相应权限@PreAuthorize(身份,或者权限)可访问

把 订单 存储在Redis 采用 hash类型 结构 ,因为一个用户就一个购物车,不能重复,用key是 userId,而且其他结构每次查询购物车中的商品需要遍历

key是 userId(namespace) :

->key1商品ID, CatOItem(name,图片,数量,price,等)

->key2商品ID, CatItem(name,图片,数量,price,等)

->key3 商品ID, CatItem(name,图片,数量,price,等)

加入购物车

实现步骤:

加入购物车:

1.获取加入商品CartItem和userID作为参数

2.查询商品详情,使用openfeign调用skuFeign和spufeign

3.先查询userID的redis购物车,在购物车中是否商品id,有就改变数量就行,没有就新增

3.把用户要添加的商品封装在CatItem

4.采用 hash类型存入redis key: cat_username put (商品id,CatItem)

查询购物车列表:

1.查询userID,有购物车?没有就返回空。有就查询

2.获取redist 的key :cat_username 所有 的value (redisTemplate.boundHashOps(“Cart”+username))

当添加购物车里的商品数量<=0,需要移除该商品信息 delete(id)

当购物车没商品,移除购物车,判断key :cat_username 的size==0,delete

在这里插入图片描述
用户要想将商品加入购物车,必须得先登录授权,登录授权后再经过微服务网关,微服务网关需要过滤判断用户请求是否存在令牌,如果存在令牌,才能再次访问微服务,此时网关会通过过滤器将令牌数据再次存入到头文件中,然后访问模板渲染服务,模板渲染服务再调用订单购物车微服务,此时也需要将令牌数据存入到头文件中,将令牌数据传递给购物车订单微服务,到了购物车订单微服务的时候,此时微服务需要校验令牌数据,如果令牌正确,才能使用购物车功能,并解析令牌数据获取用户信息。

微服务间调用的令牌认证(令牌的传递)

因为微服务之间并没有传递头文件,所以我们可以定义一个拦截器,每次微服务调用之前都先检查下头文件,将请求的头文件中的令牌数据再放入到header中,再调用其他微服务即可。

public class FeignInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        try {
            //使用RequestContextHolder工具获取request相关变量,
            //用户当前用户请求的所有数据,包含请求头,和请求参数等
            //用户当前请求的时候对应线程的数据,
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                //取出request
                HttpServletRequest request = attributes.getRequest();
                //获取所有头文件信息的key
                Enumeration<String> headerNames = request.getHeaderNames();
                if (headerNames != null) {
                    while (headerNames.hasMoreElements()) {
                        //头文件的key
                        String name = headerNames.nextElement();
                        //头文件的value
                        String values = request.getHeader(name);
                        //将令牌数据添加到头文件中
                        requestTemplate.header(name, values);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

项目最大困难

问题:

服务间使用feign调用时,会报Feign调用无效异常,debug获取当前线程请求的数据为空,很奇怪

原因:

feign配置开启熔断的是当前线程,默认是线程池隔离,会开启新的线程,

解决:

需要将熔断策略换成信号量隔离,此时不会开启新的线程,熔断策略strategy: SEMAPHORE

#开启Feign的熔断:默认是线程池隔离
feign:
  hystrix:
  	enable: true
#hystrix 配置 信号量隔离
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 10000
          strategy: SEMAPHORE

在这里插入图片描述

订单系统

添加订单

订单表

CREATE TABLE `tb_order` (
  `id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT '订单id',
  `total_num` int(11) DEFAULT NULL COMMENT '数量合计',
  `total_money` int(11) DEFAULT NULL COMMENT '金额合计',
  `pre_money` int(11) DEFAULT NULL COMMENT '优惠金额',
  `post_fee` int(11) DEFAULT NULL COMMENT '邮费',
  `pay_money` int(11) DEFAULT NULL COMMENT '实付金额',
  `pay_type` varchar(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付类型,1、在线支付、0 货到付款',
  `create_time` datetime DEFAULT NULL COMMENT '订单创建时间',
  `update_time` datetime DEFAULT NULL COMMENT '订单更新时间',
  `pay_time` datetime DEFAULT NULL COMMENT '付款时间',
  `consign_time` datetime DEFAULT NULL COMMENT '发货时间',
  `end_time` datetime DEFAULT NULL COMMENT '交易完成时间',
  `close_time` datetime DEFAULT NULL COMMENT '交易关闭时间',
  `shipping_name` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流名称',
  `shipping_code` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT '物流单号',
  `username` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '用户名称',
  `buyer_message` varchar(1000) COLLATE utf8_bin DEFAULT NULL COMMENT '买家留言',
  `buyer_rate` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否评价',
  `receiver_contact` varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人',
  `receiver_mobile` varchar(12) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人手机',
  `receiver_address` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '收货人地址',
  `source_type` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '订单来源:1:web,2:app,3:微信公众号,4:微信小程序  5 H5手机页面',
  `transaction_id` varchar(30) COLLATE utf8_bin DEFAULT NULL COMMENT '交易流水号',
  `order_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '订单状态,0:未完成,1:已完成,2:已退货',
  `pay_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '支付状态,0:未支付,1:已支付,2:支付失败',
  `consign_status` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '发货状态,0:未发货,1:已发货,2:已收货',
  `is_delete` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否删除',
  PRIMARY KEY (`id`),
  KEY `create_time` (`create_time`),
  KEY `status` (`order_status`),
  KEY `payment_type` (`pay_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

订单详情表

REATE TABLE `tb_order_item` (
  `id` varchar(50) COLLATE utf8_bin NOT NULL COMMENT 'ID',
  `category_id1` int(11) DEFAULT NULL COMMENT '1级分类',
  `category_id2` int(11) DEFAULT NULL COMMENT '2级分类',
  `category_id3` int(11) DEFAULT NULL COMMENT '3级分类',
  `spu_id` varchar(20) COLLATE utf8_bin DEFAULT NULL COMMENT 'SPU_ID',
  `sku_id` bigint(20) NOT NULL COMMENT 'SKU_ID',
  `order_id` bigint(20) NOT NULL COMMENT '订单ID',
  `name` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '商品名称',
  `price` int(20) DEFAULT NULL COMMENT '单价',
  `num` int(10) DEFAULT NULL COMMENT '数量',
  `money` int(20) DEFAULT NULL COMMENT '总金额',
  `pay_money` int(11) DEFAULT NULL COMMENT '实付金额',
  `image` varchar(200) COLLATE utf8_bin DEFAULT NULL COMMENT '图片地址',
  `weight` int(11) DEFAULT NULL COMMENT '重量',
  `post_fee` int(11) DEFAULT NULL COMMENT '运费',
  `is_return` char(1) COLLATE utf8_bin DEFAULT NULL COMMENT '是否退货,0:未退货,1:已退货',
  PRIMARY KEY (`id`),
  KEY `item_id` (`sku_id`),
  KEY `order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
情景支付状态(0未支付1支付2退款中3已退款)发货状态(0未发货1已发货2已收货)是否删除(0,1)订单状态(0 未完成 1完成 2退货中3已退货)评价信息
下订单未支付0未支付未发货10未完成
下订单未支付1支付未发货11完成
发货1支付发货11完成
收货1支付收货11完成0
退货中2退款中0未发货12退货中
退货中2退款中1发货12退货中
收到退货3已退款2已收货13退货
0

从购物车中下订单

  1. 从token中获取userId,设置给order
  2. 订单ID生成,采用Idwork,雪花算花,
  3. 在购物车中列一个字段属性 封装购物车中的被勾选的商品id集合,遍历查询对应购物车的商品添加到新建集合OrderItems订单明细表中,
  4. 订单的属性: 订单号,订单状态,收货人,收货地址,收获联系方式,商品属性,商品数量,商品单价,下单时间,支付时间,发货时间,收货时间
  5. 遍历OrderItems订单明细中的商品添加属性(购买商品总数量 ,总金额,实付金额)到OrderItem订单中
  6. 提交订单后,从购物车中移除已经提交的商品,并调用商品系统微服务 减少相应商品的库存

解决超卖问题

方案一:

Redis 中setnx 命令是对key设置分布式锁 : 如果key (商品id)不存在的时候,就把key设置成value(UUID,当作锁的标示),若key存在就不做改变(注意:对key (商品id)设置生效时间,以防redis宕机死锁,到时间自动释放)

try{

获取库存,-1

}finally{

高并发的情况会发生超出锁的有效时间自动释放当前锁,而在这个位置释放了 后面获取这把锁线程 , 导致最开始的商品的锁 ,死锁,给锁做标记uuid(value),判断当前的value.equals(get(key)){

释放锁,以防死锁,删除key

}

}

方案二: 可以解决方案一的最开始因系统压力,运行时间超有效时间发生的死锁问题

使用Redission 分布式锁,是多个Redission线程依次给key (商品id)加锁,但是只能加一个锁,其他Redission线程会自循环判断key (商品id)的锁是否释放,释放了才可以再加一个锁,其中,Redission线程,会执行一个分线程,判断每隔 1/3的有效时间 是否还有锁,如果有给锁延长时间,在finally最后手动释放锁

redissionlock.lock(30s)

try{

获取库存,-1

}finally{

redissionlock.unlock()

释放锁,以防死锁,

}

}

在这里插入图片描述

zookeepr可以解决 redis主从架构的宕机问题,但是性能不如Redis

在这里插入图片描述

发送 -》延时队列30分钟(死信交换机,死信队列)–》队列(监听)

死信队列:过了一定的时间,有效期过了,但数据并没有被读取过,

在这里插入图片描述

秒杀系统

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值