使用分库分表,给订单相关设置分表,订单号作为分表依据
商品库:商品sku表、sku属性表、sku图片表、商品spu表、spu属性表、spu图片表、商品品牌表、三级分类表等
一个sku关联多个spu表,
订单库:订单表、订单详情表、订单退款表、支付信息表、退货表、退款表、退货原因表
订单表相关表都用订单id相关联
会员库:会员表、会员等级表、会员收货地址、会员登陆记录表、会员收藏商品表、会员积分表、会员积分历史变化表
库存库:仓库表、商品库存表、采购信息表、库存工作单
管理员库:系统日志、角色表、菜单表、角色和菜单表、用户token表、系统验证码、系统日志表
优惠库:秒杀活动场次表、秒杀活动商品关联、会员价格表、优惠券信息、优惠券领取记录、优惠券与商品关联表、积分信息表
购物车:商品表,品牌表,分类表,库存表,用户表,库房表,购物车表,购物项表,优惠券表,商品推荐表。
登录模块1.前后端对数据进行校验,请求进入后台
2.根据用户名或者手机号在数据中查询,并把数据加密的结果,和登录密码进行利用BCryptPasswordEncoder
的matches
方法比对
3.比对成功返回
注册模块1、前端判断用户输入参数格式
2、注册时需要输入手机短信验证码
3、首次注册把验证码存储在redis中,然后设置过期时间,1分钟
4、再发送验证的时候判断redis中,验证码是否过期,没过期不给予重发
5、登录的时候,获取存入Redis里的验证码,不为空验证通过删除验证码
6、输入账号密码点击注册,首先会判断redis中有没有该手机号的验证码
7、对比成功删除验证码,跳转到会员服务注册验证手机号用户名是否存在
8、不存在重复的就注册成功,然后跳转到用户登录页面
9、输入用户名密码,去数据库对比账户,密码用BCryptPasswordEncoder的matches方法
10、对比成功就把用户数据存在session中
会员服务拦截器会从请求中获取session,从中获取用户的信息,然后保存在ThreadLocal副本中,在其他方法中传递
OAuth2授权验证登录用户登录请求授权,点击同意授权
-
会向认证中心申请的几个参数:client_id(客户端唯一id)、client_secret(客户端密钥)等等信息
-
带上这些参数向微博的认证中心获取授权码code
-
微博认证中心返回Authorization Code授权验证码
-
然后携带授权码发送请求给认证中心获取令牌Access Token
-
认证中心收到令牌会返回一段json数据,包含Access Token
{ "access_token":"ACCESS_TOKEN", "token_type":"bearer", "expires_in":2592000, "refresh_token":"REFRESH_TOKEN", "scope":"read", "uid":100101 }
-
携带这个json里面的令牌access_token去获取微博里面的用户信息
注销
购物车模块未登录用户只能存20个数据,已登录用户只能存50个数据
未登录用户购物车只能存放在浏览器cookie中
已登录用户购物车存放在redis中
展示购物车是,如果用户登录了还要把cookie中的商品和已登录的商品进行合并
获取购物车- 没登陆是临时用户,从浏览器的cookie获取购物车信息
- 已登录情况下就是当前用户购物车,从redis中获取
- 没登陆并且是临时用户,需要创建一个临时用户
获取购物车具体逻辑
1、方法请求之前,通过HandlerInterceptor
拦截器获取用户登录或者未登录用户的信息
2、先从request请求里面获取session里面当前登录的用户,如果没有的话遍历获取浏览器cookie
3、查询cookie里面有没有user-key,没有的话配一个临时用户
4、临时用户user-key为随机生成的uuid,并标记为临时用户
5、把这些信息存放到ThreadLocal里面
6、获取购物车方法里面,取得当前拦截器的ThreadLocal,得到用户信息
7、如果用户信息不为空,说明已登录,
8、在所有方法执行完毕之后,如果当前用户不是临时用户把当前用户信息保存到浏览器
添加购物车具体逻辑-
根据当前用户的id获取redis中的购物车数据,拿当前需要添加的商品skuid和redis中的数据对比
-
如果有相同的数据,只需要增加购物车中的数量
-
如果redis中没有该商品,那么就新增进去
-
新增操作:远程调用商品服务根据skuid查询该商品的信息,还有该属性的信息库存数量等等
封装成购物车的实体,重新放入原来的购物车中
去结算分别远程调用
- 遍历重新获取购物车商品的价格
- 获取用户的地址
- 获取商品的库存信息
采用异步编排操作等待以上所有执行完
并生成唯一令牌保存在redis中过期时间30分钟,多次提交订单防重,重复提交的话每次都会生成新的token,之前的token会失效
成功生成确认订单的实体
提交订单逻辑创建事务
-
去验令牌
- 创建订单的时候就会生成令牌token,然后存储在redis中,提交订单会再次核验是否redis有对应令牌,有的话删除令牌,没有的话不予再次提交订单。令牌的确认和删除需要保障原子性,利用redis的lua脚本进行操作
-
创建订单
-
生成订单号(时间戳)
-
获取选中购物车的所有项,创建订单项
-
获取收货人信息填充订单
-
计算订单金额
-
-
验价格
- 再次获取购物项,获取价格,之后提交订单以这个价格为准
-
构建订单项
每个sku商品的信息
-
保存订单、以及订单项
-
锁定库存
方法加上事务
根据传入的订单项,拿商品的id去仓库表查询就近仓库,返回有库存的仓库
然后遍历仓库查询是否有该商品的库存数量,仓库没有该商品就抛出异常
有库存的去库存表更新,减去库存数量,并增加锁定库存数量,如果没有锁住抛出异常
最后锁库存成功
把消息发送给MQ,设置30分钟过期时间,延时队列,没有被消费就解锁库存
2.下单成功来支付选择页
3.下单失败回到订单页重新确认提交信息
库存解锁逻辑1、下订单成功,订单过期没有支付被系统自动取消或者用户手动取消,都要解锁库存
2、下订单成功、库存锁定成功,但是业务调用失败导致订单回滚,之前锁定的库存就自动解锁,Seata分布式事务太慢,就要用一段时间后自动解决库存。
3、订单失败,因为锁库存失败有一个商品没有锁成功,导致整个锁库存服务都回滚,
取消、超时未支付关闭订单逻辑订单创建后,默认放入延时队列,也就是订单的有效时间,超过这个时间没有支付或者用户主动取消都会导致订单信息进入order.release.order.queue
队列,最后被释放
传入支付信息(总价等等)
调用支付宝接口pay方法,到支付宝客户端
在客户端创建一个支付请求客户端生成请求
自动来到支付宝的收银台页面
支付之后跳转到支付成功页面
关闭订单逻辑手动关闭和自动关闭
会发送一条消息到订单交换机,订单交换机分发到库存解锁队列、优惠券返还队列、释放订单队列
数据库保存每一条消息的详细信息,定期扫描数据库将失败的消息再发送一遍
秒杀商品上架定时任务使用分布式锁防止定时任务重复执行,查询3天内需要上架的秒杀商品,查询完之后解锁
然后把扫描到的商品活动信息放入redis中
秒杀的起止时间作为key,场次和商品id作为value存入redis中
引入分布式锁的信号量,秒杀的数量作为信号量 一个秒杀减一个
利用商品随机码随机生成的token设置分布式信号量,秒杀的数量作为信号量 一个秒杀减一个
秒杀商品逻辑1、先判断是否登录,利用mvc视图监听
2、点击页面秒杀按钮,后台获取秒杀的商品Id信息,还有随机码、商品数量
3、根据商品ID去redis查询sku信息,从集合中获取到商品的json数据再转为实体
4、利用之前存储的随机校验码,和页面获取到的效验码对比,验证购买数量
5、然后根据商品的key值和当前用户id拼接作为新的key值存入redis ,并设置过期时间,可以防止同一个用户同一时间多次秒杀到同一个商品
6、根据随机码获取到信号量,扣去信号量
7、整合成订单实体,快速向消息丢列发送订单消息,监听队列
8、队列调用创建订单的方法,并保存
9、同时发送数据至页面,页面识别到已生成订单号就转发至支付宝支付
10、支付成功之后,自动调用回调方法修改订单成已支付状态
秒杀完成
订单提交逻辑-
去验令牌
- 创建订单的时候就会生成令牌token,然后存储在redis中,提交订单会再次核验是否redis有对应令牌,有的话删除令牌,没有的话不予再次提交订单。令牌的确认和删除需要保障原子性,利用redis的lua脚本进行操作
-
创建订单
-
生成订单号
-
获取选中购物车的所有项,创建订单项
-
获取收货人信息填充订单
-
计算订单金额
-
-
验价格
- 再次获取购物项,获取价格,之后提交订单以这个价格为准
-
构建订单项
每个sku商品的信息
-
保存订单、以及订单项
-
锁定库存
方法加上事务
根据传入的订单项,拿商品的id去仓库表查询就近仓库,返回有库存的仓库
然后遍历仓库查询是否有该商品的库存数量,仓库没有该商品就抛出异常
有库存的去库存表更新,减去库存数量,并增加锁定库存数量,如果没有锁住抛出异常
最后锁库存成功
2.下单成功来支付选择页
3.下单失败回到订单页重新确认提交信息