当前位置: 首页 > news >正文

黑马点评面试前复习

文章目录

      • 1.短信登录
        • 1.1 问题1:基于session你是如何实现短信登录的?
        • 1.2 问题2:为什么用redis代替session存储?
        • 1.3 问题3:如何基于redis实现短信登录?
        • 1.4 问题4:用户一直在访问的过程中,突然用户登录的redis过期?
        • 1.4 问题5:上述拦截的路径都是需要登录的,如果用户访问的是不需要登录的怎么办?token还是会过期了
      • 2.商铺查询缓存
        • 2.1 问题1:请你谈谈添加redis缓存的逻辑
        • 2.2 问题2:缓存更新策略有哪些,一般如何选择?
        • 2.3 问题3:操作缓存和数据库是删缓存还是更新缓存?
        • 2.4 问题4:一般是先删缓存还是先操作数据库?
        • 2.5问题5:什么是缓存穿透?如何解决缓存穿透问题?
        • 2.6问题6:什么是缓存雪崩?如何解决缓存雪崩问题?
        • 2.7 问题7:什么是缓存击穿?如何解决缓存击穿?
        • 2.8问题8:逻辑过期时间你具体是怎么设置进去的呢?
      • 3.优惠券秒杀
        • 3.1问题1: 秒杀订单的主键一般如何设置
        • 3.2问题2:实现优惠券秒杀下单的流程是如何的?
        • 3.3 问题3:为什么会出现超卖问题?如何解决超卖问题?
        • 3.4 问题4:乐观锁解决失败率高什么情况如何解决?
        • 3.5 问题5:如何实现一人一单的功能呢?
      • 4.分布式锁
        • 4.1 问题1:锁监视器一般一个jvm对应一个,如果集群模式下如何保证锁成功?
        • 4.2 问题2:什么是分布式锁?如何使用
        • 4.3 问题3:另一个方法想要调用定义了事务的方法,事务如何生效?
        • 4.4问题4:线程1业务阻塞锁超时释放,导致线程2获取锁业务没执行完,线程1释放锁问题如何解决?
        • 4.5问题5:判断锁标识通过到释放锁中间业务阻塞,这可能导致释放别的线程的锁,如何解决?
        • 4.6问题6:基于setnx实现的分布式锁有哪些可以优化的地方?
      • 5.秒杀优化
        • 5.1问题1:上述秒杀都在mysql实现,效率较低如何优化?
        • 5.2 问题2:基于阻塞队列实现会有什么问题?

1.短信登录

1.1 问题1:基于session你是如何实现短信登录的?

1.用户提交发送请求验证码。后端校验用户手机号是否正确,正确的话先保存验证码和手机号到session,并返回验证码到前端
2.用户点击登录。校验手机号和验证码是否和服务端存储再session一致,一致再判断手机号再数据库是否存在,存在,保存到session中。不存在用户信息保存到数据库,再写入session中
3.实现登录校验。自定义一个登录拦截器,获取请求中携带的sessionid,再从session中找到对应的user信息,并保存用户信息到ThreadLocal当中,然后放行

1.2 问题2:为什么用redis代替session存储?

1.session只能存储在某一个tomcat服务器内,如果出现多台tomcat前端访问并不知道自己的信息存储在哪一台,因此需要使用redis存储session,并且redis也刚好符合内存存储,可以实现数据共享,并且是键值对形式存储

1.3 问题3:如何基于redis实现短信登录?

1.用户点击请求验证码。后端生成验证码,并把(手机号,验证码)设置为键值对存储到redis中,并设置有效期
2.用于点击登录的时候,校验手机号通过,判断发送的验证码和redis中该手机号存储验证码是否一致,通过的话。查询数据库,用户信息以Hash形式存储到redis中,其中以UUID生成的随机值作为key(token),并将其返回给前端。并为redis这组数据设置30min有效期

1.4 问题4:用户一直在访问的过程中,突然用户登录的redis过期?
  1. 依然可以在登录校验中进行设置,登录拦截器中获取前端传递的token,从token中获取redis用户,并将用户保存到threadLocal当中,并重置时间为30分钟,因此只要有请求经过了拦截器,就会刷新时间
1.4 问题5:上述拦截的路径都是需要登录的,如果用户访问的是不需要登录的怎么办?token还是会过期了

1.再添加一层拦截器,拦截所有请求路径,把保存ThreadLocal和刷新的动作都放在这里执行 。第一个拦截器没有token或者没有用户直接放行。第二个拦截器判断ThreadLocal是否有值,无就拦截

2.商铺查询缓存

2.1 问题1:请你谈谈添加redis缓存的逻辑

1.用户发起请求,先到redis中查询缓存,缓存命中返回,未命中,查询数据,数据写入redis,再返回给前端

2.2 问题2:缓存更新策略有哪些,一般如何选择?

有内存淘汰,超时剔除,主动更新。内存淘汰是redis内部内存不足,自动淘汰部分数据。超时剔除是给缓存添加过期时间,到期自动删除。主动更新是编写业务逻辑,修改数据库的同时修改缓存。
低一致性需求时:内存淘汰机制。如店铺类型的查询缓存
高一致性需求时:主动更新+超时剔除。如店铺的详情信息

2.3 问题3:操作缓存和数据库是删缓存还是更新缓存?

一般选择删缓存,更新数据库,直接删除缓存,等查询的时候再更新缓存(事务保证同成功/失败)。如果是更新缓存的话,如果数据库更新N次,缓存也要更新N次,压力较大

2.4 问题4:一般是先删缓存还是先操作数据库?

一般是先操作数据库再删缓存。如果是线程1先删缓存,线程2查缓存未命中,查数据库,更新缓存。线程1再更新数据库,此时容易出现数据不一致性的问题。缓存操作一般是微秒级别的,更新数据库较慢,因此这种情况容易发生。
先操作数据库再删缓存。可以大大避免这种情况。先执行慢操作,再执行快操作,降低两者之间其他线程趁虚而入的可能性。

2.5问题5:什么是缓存穿透?如何解决缓存穿透问题?

缓存穿透指的是客户端请求的数据在缓存和数据库中都不存在,这样缓存不会生效,请求都打到数据库里面。
被动: 采用缓存空对象的形式,存到redis中,并设置较短的过期时间
主动:增加id复杂度,做好基础的格式校验,加强用户权限

2.6问题6:什么是缓存雪崩?如何解决缓存雪崩问题?

缓存雪崩指的是同一时段大量缓存的key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
给不同的key的TTL添加随机值
给业务添加多级缓存

2.7 问题7:什么是缓存击穿?如何解决缓存击穿?

缓存击穿问题也称为热点key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效,无数请求访问数据库带来巨大压力。
解决方案:给缓存重建加互斥锁,一个重建,其他线程等待。或者设置逻辑过期时间,交给另一个线程做缓存重建逻辑(开启互斥锁),自己返回旧数据给请求。前者维护一致性,后者维护可用性

2.8问题8:逻辑过期时间你具体是怎么设置进去的呢?

重新定义一个类,定义逻辑过期字段,和data字段用来存放原本的店铺数据。然后函数new这个类,把这两个字段的数据放进去

3.优惠券秒杀

3.1问题1: 秒杀订单的主键一般如何设置

使用全局ID生成器,(符合位+31位时间戳+32位序列号),序列号是redis自增的数据。
也可以使用UUID生成,但是都是随机的。不够友好

3.2问题2:实现优惠券秒杀下单的流程是如何的?

前端提交优惠券的id,查询优惠券信息,判断是否开始或结束,判断库存是否充足,都满足就返回订单的id给前端

3.3 问题3:为什么会出现超卖问题?如何解决超卖问题?

库存剩下1的时候,100个线程进来查询,有部分刚好同时查询到库存等于1,都执行扣减操作,就会出现超卖问题。
解决超卖问题:1.版本号法,数据库字段增减一个版本号字段,修改了库存,版本号加一,其他线程修改判断不一致就停止修改
2.CAS法:直接拿库存本身做判断 ,比较数据有没有发生变化
总结:更新时候查询的版本和之前查询到的版本是否一致
3.悲观锁,直接给更新的部分加锁

3.4 问题4:乐观锁解决失败率高什么情况如何解决?

库存大于0的时候,就让他执行更新操作,不是更新查询的库存和之前的库存一致。因为库存大于0的时候并发修改时不会造成超卖问题的

3.5 问题5:如何实现一人一单的功能呢?

扣库存之前,添加判断订单表里面用户id和优惠券id是否已经存在,存在就拒接执行。同时给这段代码加悲观锁方案(因为乐观锁方案是用在更新操作上的)

4.分布式锁

4.1 问题1:锁监视器一般一个jvm对应一个,如果集群模式下如何保证锁成功?

使用分布式锁方案,jvm外部的一个锁监视器

4.2 问题2:什么是分布式锁?如何使用

分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁。
利用redis的setnx方法实现互斥效果,并设置超时释放,如果获取锁了返回true,其他线程想获取就会返回false

4.3 问题3:另一个方法想要调用定义了事务的方法,事务如何生效?

因为事务时被spring生成动态代理得,直接调用该方法,使用得时本地方法,没有事务功能,所以要用AopContext.currentProxy().对应方法获取到代理对象,此时该方法就有事务功能
同时pom文件添加aspectjweaver依赖
启动类添加注解暴露代理对象@EnableAspectJAutoProxy(exposeProxy=true)

4.4问题4:线程1业务阻塞锁超时释放,导致线程2获取锁业务没执行完,线程1释放锁问题如何解决?

释放锁的时候,添加一个锁标识,判断是不是自己的锁,再决定是否释放锁

4.5问题5:判断锁标识通过到释放锁中间业务阻塞,这可能导致释放别的线程的锁,如何解决?

需要判断锁标识和释放操作的原子性
使用lua脚本实现分布式锁的释放锁逻辑,主要调用的是redis.call方法
使用RedisTemplate调用lua脚本,stringRedisTemplate.execute()方法

4.6问题6:基于setnx实现的分布式锁有哪些可以优化的地方?

1.不可重入问题
2.不可重试。获取锁只尝试一次就返回false,没有重试机制
3.超时释放。原本业务执行时间就较长
4.主从一致性。如果Redis提供主从集群,主从同步存在延迟,当主宕机时,从未同步完成主的锁节点,新的线程进来就又会setnx,导致锁失效。
解决方案,推荐使用redisson(内置分布式锁的实现方案等等)
redisson也可以实现可重入的作用,实现原理何Reentertlock一致,内部维护一个锁计数器。
利用watchDog延续锁时间,利用信号量设置锁重试等待
Redisson的multiLock,设置多个独立的redis节点,所有节点都获取可重入锁,才算获取锁成功

5.秒杀优化

5.1问题1:上述秒杀都在mysql实现,效率较低如何优化?

将判断库存和一人一单的功能放在redis执行,通过Lua脚本实现。生成订单,先返回给前端。至于真的下单的操作异步执行,通过阻塞队列操作就行。

5.2 问题2:基于阻塞队列实现会有什么问题?

1.jvm内存限制问题,超出jvm内存溢出
2.jvm内存安全问题,服务重启阻塞队列内容丢失

http://www.xdnf.cn/news/486667.html

相关文章:

  • 探索大型语言模型(LLM)的开源学习路径:mlabonne/llm-course 深度解析
  • 多模块,依赖android.car.jar后,能调用接口但是没有回调的问题
  • 电子电路仿真实验教学平台重磅上线!——深圳航天科技创新研究院倾力打造,助力高校教学数字化转型
  • Linux进程信号(一)之信号的入门
  • AI-Course-Presenter
  • Houdini POP入门学习01
  • 后端框架(1):Mybatis
  • “分布形态“
  • 浅谈“量子计算应用:从基础原理到行业破局”
  • ohttps开启群晖ssl证书自动更新
  • lesson03-简单回归案例(理论+代码)
  • 文章记单词 | 第87篇(六级)
  • FC7300 ADC MCAL配置引导
  • sqli-labs靶场23-28a关(过滤)
  • conda init执行了还是不好用
  • 2025年长三角+山东省赛+ 认证杯二阶段论文发布!
  • python是如何调用前后双下划线的函数的
  • mysql集群
  • [前端] wang 富文本 vue3
  • 【GaussDB迁移攻略】DRS支持CDC,解决大规模数据迁移挑战
  • 芯谷产业园:双流元宇宙开放数字贸易新坐标
  • C++:字符串操作函数
  • 刷leetcodehot100返航版--双指针5/16
  • 虚拟来电 4.3.0 |集虚拟来电与短信于一体,解锁VIP优雅脱身
  • 腾讯云代码助手CodeBuddy使用体验
  • 7.1Java多线程安全和同步
  • vue 指令
  • python版本管理工具-pyenv轻松切换多个Python版本
  • DATE_FORMAT可以接收date类型,也可以接收String类型!
  • this.$set的用法-响应式数据更新