我是靠谱客的博主 着急月饼,最近开发中收集的这篇文章主要介绍Java双检锁防止Redis缓存穿透(模板方法设计模式)1、抽象出双重检测模板方法2、持久层查询统一接口3、业务代码中调用模板方法,实现数据查询功能4、持久层userDao的方法(基本功自己实现吧)5、userMapper.xml的省略,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
在高并发项目中,为了缓解数据库查询压力,通常会引入Redis等非关系型数据库作为缓存。
查询数据的一般步骤为:
step1、查询缓存。
step2、判断是否为空。
如果不为空:
step3、返回查询结果。
如果为空:
step3、查询数据库(数据库没有Redis性能高,通常会有一两秒的延迟,假设2秒)。
step4、更新Redis缓存。
step5、返回查询结果。
在高并发情况下,假设有10个请求顺序进入查询方法,因为查询数据库有一定的时间延迟,导致每个请求都查询不到缓存,容易发生10个请求都查询数据库的情况,这就叫缓存穿透现象。
解决方案如下:
1、抽象出双重检测模板方法
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、持久层查询统一接口
package com.video.cache;
/**
* 持久层查询接口
* 公共接口
* @author 张宇乐
*
* @param <T>
*/
public interface BaseServiceHandler<T> {
public T load();
}
3、业务代码中调用模板方法,实现数据查询功能
@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的方法(基本功自己实现吧)
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的方法(基本功自己实现吧)5、userMapper.xml的省略所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复