Time: 2024-10-21 Monday 08:42:01
Author: Jackasher
Redis-黑马
直接跳过基本操作和 Jedis 操作开始实战,然后我们重点是学会 redis 的思想,而不是编码,所以直接拿着现成项目学习, 而不是一个一个敲,
手机号模拟验证码和登入
把生成验证码保存到 session 后, 返回给前端, 前端输入验证码,服务器进行验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| @Override public Result sedCode(String phone, HttpSession session) { if (RegexUtils.isPhoneInvalid(phone)) { return Result.fail("手机号格式错误"); }
String code = RandomUtil.randomNumbers(6); session.setAttribute("code",code); log.debug("发送短信验证码成功,验证码:{}",code); return Result.ok(); }
@Override public Result login(LoginFormDTO loginForm, HttpSession session) { String phone = loginForm.getPhone(); if (RegexUtils.isPhoneInvalid(phone)) { return Result.fail("手机号格式错误"); } Object cacheCode = session.getAttribute("code"); String code = loginForm.getCode(); if (cacheCode == null || !cacheCode.toString().equals(code)){ return Result.fail("验证码错误"); }
User user = query().eq("phone", phone).one();
if (user == null){ user = createUserWithPhone(phone); }
session.setAttribute("user",BeanUtil.copyProperties(user,UserDTO.class)); return Result.ok(); }
|
Session 到底是个什么
用户打开浏览器, 默认会有一个 sessionid, 在发生请求时, 自动发送到服务器, 所以不需要一个返回凭证
拦截器
1
| public class LoginInterceptor implements HandlerInterceptor
|
这是 Spring 配置拦截器的类,注册到容器里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.hmdp.config;
import com.hmdp.utils.LoginInterceptor; import com.hmdp.utils.RefreshTokenInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
@Configuration public class MvcConfig implements WebMvcConfigurer {
@Resource private StringRedisTemplate stringRedisTemplate;
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) .excludePathPatterns( "/shop/**", "/voucher/**", "/shop-type/**", "/upload/**", "/blog/hot", "/user/code", "/user/login" ); } }
|
BeanUtil
这是 javaJDk 提供的包, 可以把一个对象的属性粘贴在另一个对象, 也可以把 bean 转成 map, 把 map 转出 bean
1 2 3 4 5
| UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
Map<String, Object> stringObjectMap = BeanUtil.beanToMap(userDTO);
Map<String, Object> stringObjectMap = BeanUtil.beanToMap(userDTO);
|
StrUtil
StrUtil.isBlank(token) 是来自 Hutool 工具库的一个方法,它的作用是检查字符串是否为以下三种情况之一:
•null
•字符串(“”)
•仅包含空白字符(如空格、制表符等)
Redis 速度
首先看看从数据库查数据的返回速度,可以看到是 884ms,听说 redis 是微秒级别的,我们来看看吧

可以看到第二次的查询速度直接数量级的下降了,直接变成 71ms 了,这就是 redis 的速度

缓存穿透
缓存穿透是指, 客户请求的数据不存在, 每一次请求都会打到数据库, 解决方法是布隆过滤和缓存空对象, 这里的演示缓存空对象, 原理就是把这个不存在 的 key 放在 redis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @Override public Result queryById(Long id) { String key = CACHE_SHOP_KEY + id; String shopJson = stringRedisTemplate.opsForValue().get(key); if (StrUtil.isNotBlank(shopJson)) { Shop shop = JSONUtil.toBean(shopJson, Shop.class); System.out.println("redis 存在该数据"); return Result.ok(shop); } if (shopJson != null) { return Result.fail("店铺不存在"); } Shop shop = getById(id); if (shop == null) { stringRedisTemplate.opsForValue().set("cache:shop:" + id, "", 5L, TimeUnit.MINUTES); return Result.fail("店铺不存在"); } if (shop != null) { stringRedisTemplate.opsForValue().set("cache:shop:" + id, JSONUtil.toJsonStr(shop), CACHE_SHOP_TTL, TimeUnit.MINUTES); return Result.ok(shop); } return Result.ok(shop); }
|
通过格式校验也可以解决缓存穿透,还有SpringCloud
的限流

缓存雪崩
缓存雪崩就是 redis 宕机了,或者同一时间大量缓存 key 过期,造成大量访问数据库了,
解决方案
- 给 Key 的 ttl 设置不同的时间段
- 集群
- 限流
- 多级缓存
缓存击穿
缓存击穿, 就是某一个常用的 key 失效了, 然后大量请求直接打向数据库
BooleanUtil.isTrue
BooleanUtil
的 isTrue
方法用于判断传入的布尔值是否为 true
。它通常用来简化布尔值的判断逻辑,避免对 null
值进行显式的处理。
具体而言,isTrue
方法的实现通常会判断传入的对象是否为 true
,并且会自动处理 null
的情况。伪代码如下:
1 2 3
| public static boolean isTrue(Boolean bool) { return bool != null && bool; }
|
功能总结:
- 如果传入的值为
true
,返回 true
。
- 如果传入的值为
false
或 null
,返回 false
。
这个方法可以防止 NullPointerException
,避免手动去写 bool != null && bool == true
的复杂判断。
结束
决定不听了,实在是讲的太差了, 真的不知道怎么回去推荐黑马的课程,太荒唐了, 根本不是给初学者看的