⑤. 查询代码展示
(这里补充一个在工作中实际遇到过的案例:公司某个卡卷活动,送保养给客户,设置的是一个月,最后当那个key消失的时候,我的邮箱就收到了3条报警邮件,我们分析了一下代码,出现了缓存击穿的现象,最后我们使用周志明老师的双端检索机制,使用重量级进行加锁,进行二次if判断,重新查询数据库,将热点代码进行重新设置进去)
/** * 业务逻辑并没有写错,对于小厂中厂(QPS《=1000)可以使用,但是大厂不行 * @param id * @return */ public User findUserById(Integer id) { User user = null; String key = CACHE_KEY_USER+id; //1 先从redis里面查询,如果有直接1返回结果,如果没有再去查询mysql user = (User) redisTemplate.opsForValue().get(key); if(user == null) { //2 redis里面无,继续查询mysql user = userMapper.selectByPrimaryKey(id); if(user == null) { //3.1 redis+mysql 都无数据 //你具体细化,防止多次穿透,我们规定,记录下导致穿透的这个key回写redis return user; }else{ //3.2 mysql有,需要将数据写回redis,保证下一次的缓存命中率 redisTemplate.opsForValue().set(key,user); } } return user; } /** * 加强补充,避免突然key实现了,打爆mysql,做一下预防,尽量不出现击穿的情况。 * @param id * @return */ public User findUserById2(Integer id) { User user = null; String key = CACHE_KEY_USER+id; //1 先从redis里面查询,如果有直接返回结果,如果没有再去查询mysql user = (User) redisTemplate.opsForValue().get(key); if(user == null) { //2 大厂用,对于高QPS的优化,进来就先加锁,保证一个请求操作,让外面的redis等待一下,避免击穿mysql synchronized (UserService.class){ user = (User) redisTemplate.opsForValue().get(key); //3 二次查redis还是null,可以去查mysql了(mysql默认有数据) if (user == null) { //4 查询mysql拿数据 user = userMapper.selectByPrimaryKey(id);//mysql有数据默认 if (user == null) { return null; }else{ //5 mysql里面有数据的,需要回写redis,完成数据一致性的同步工作 //setnx 不存在才创建 redisTemplate.opsForValue().setIfAbsent(key,user,7L,TimeUnit.DAYS); } } } } return user; }
⑥. 进入到redis的客户端,查看到的数据显示不正常,我们要使用–raw进入redis的客户端
127.0.0.1:6379> keys * 1) "user:1005" 2) "user:1002" 3) "user:1003" 4) "user:1004" 5) "user:1001" 127.0.0.1:6379> get user:1005 "{\"@class\":\"com.xiaozhi.redis.entities.User\",\"id\":1005,\"username\":\"TANGZHI5\",\"password\":\"a305b9\",\"sex\":0,\"deleted\":0,\"updateTime\":[\"java.util.Date\",1629181924000],\"createTime\":[\"java.util.Date\",1629181924000]}" 127.0.0.1:6379> get user:1001 "{\"@class\":\"com.xiaozhi.redis.entities.User\",\"id\":1001,\"username\":\"TANGZHI1\",\"password\":\"65156c\",\"sex\":0,\"deleted\":0,\"updateTime\":[\"java.util.Date\",1629181924000],\"createTime\":[\"java.util.Date\",1629181924000]}" 127.0.0.1:6379> exit root@459c7c8679b1:/data# redis-cli --raw 127.0.0.1:6379> get user:1001 {"@class":"com.xiaozhi.redis.entities.User","id":1001,"username":"TANGZHI1","password":"65156c","sex":0,"deleted":0,"updateTime":["java.util.Date",1629181924000],"createTime":["java.util.Date",1629181924000]} 127.0.0.1:6379> get user:1005 {"@class":"com.xiaozhi.redis.entities.User","id":1005,"username":"TANGZHI5","password":"a305b9","sex":0,"deleted":0,"updateTime":["java.util.Date",1629181924000],"createTime":["java.util.Date",1629181924000]} 127.0.0.1:6379>