我是靠谱客的博主 着急月饼,这篇文章主要介绍Java双检锁防止Redis缓存穿透(模板方法设计模式)1、抽象出双重检测模板方法2、持久层查询统一接口3、业务代码中调用模板方法,实现数据查询功能4、持久层userDao的方法(基本功自己实现吧)5、userMapper.xml的省略,现在分享给大家,希望可以做个参考。

在高并发项目中,为了缓解数据库查询压力,通常会引入Redis等非关系型数据库作为缓存。

查询数据的一般步骤为:

step1、查询缓存。

step2、判断是否为空。

如果不为空:

        step3、返回查询结果。

如果为空:

        step3、查询数据库(数据库没有Redis性能高,通常会有一两秒的延迟,假设2秒)。

        step4、更新Redis缓存。

        step5、返回查询结果。

 

在高并发情况下,假设有10个请求顺序进入查询方法,因为查询数据库有一定的时间延迟,导致每个请求都查询不到缓存,容易发生10个请求都查询数据库的情况,这就叫缓存穿透现象。

解决方案如下:

 

1、抽象出双重检测模板方法

复制代码
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.video.cache; import java.util.concurrent.TimeUnit; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Service; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; /** * 双重检测防止缓存穿透模板方法 * @author 张宇乐 * */ @Service public class CacheTemplate { @Autowired private RedisTemplate<String, String> redisTemplate; /** * * @param key 缓存key * @param clazz 返回值类型 * @param expire 缓存失效时间 * @param service 如果缓存查不到,调用持久层mapper查询数据 * @return */ public <T> T loadCache(String key, TypeReference<T> clazz, long expire,BaseServiceHandler<T> service) { //查询缓存(第一次检测缓存) ValueOperations<String, String> ops = redisTemplate.opsForValue(); String json = ops.get(key); //判断是否为空 if(StringUtils.isNotEmpty(json) && !"null".equalsIgnoreCase(json)) { return JSON.parseObject(json,clazz); } synchronized (this) { //第二次检测缓存 json = ops.get(key); if(StringUtils.isNotEmpty(json) && !"null".equalsIgnoreCase(json)) { return JSON.parseObject(json,clazz); } //查询DB T result = service.load(); //重置缓存 ops.set(key, JSON.toJSONString(result), expire, TimeUnit.MINUTES); return result; } } }

 

2、持久层查询统一接口

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.video.cache; /** * 持久层查询接口 * 公共接口 * @author 张宇乐 * * @param <T> */ public interface BaseServiceHandler<T> { public T load(); }

3、业务代码中调用模板方法,实现数据查询功能

复制代码
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
@Autowired private UserDao userDao; @Autowired private CacheTemplate cacheTemplate; //测试双重检测 -- 防止缓存穿透 @Override public User getCacheUser(String userId) { User user = cacheTemplate.loadCache(Config.getLoginUserKey(userId), new TypeReference<User>() {}, 10, new BaseServiceHandler<User>() { @Override public User load() { return userDao.selectByPrimaryKey(userId); } }); return user; } //测试双重检测 -- 防止缓存穿透 @Override public List<User> getCacheUserList() { String key = "userList"; return cacheTemplate.loadCache(key, new TypeReference<List<User>>() {}, 10, new BaseServiceHandler<List<User>>() { @Override public List<User> load() { return userDao.getAll(); } }); }

4、持久层userDao的方法(基本功自己实现吧)

复制代码
1
2
3
4
public User searchPhoto(@Param("userId") String userId); @Select("select * from user;") public List<User> getAll();

5、userMapper.xml的省略

 

推荐一个公众号

号主为一线大厂架构师,CSDN博客专家,博客访问量突破一千万。主要分享Java、golang架构,源码,分布式,高并发等技术,用大厂程序员的视角来探讨技术进阶、面试指南、职业规划等。15W技术人的选择!

最后

以上就是着急月饼最近收集整理的关于Java双检锁防止Redis缓存穿透(模板方法设计模式)1、抽象出双重检测模板方法2、持久层查询统一接口3、业务代码中调用模板方法,实现数据查询功能4、持久层userDao的方法(基本功自己实现吧)5、userMapper.xml的省略的全部内容,更多相关Java双检锁防止Redis缓存穿透(模板方法设计模式)1、抽象出双重检测模板方法2、持久层查询统一接口3、业务代码中调用模板方法,实现数据查询功能4、持久层userDao内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部