我是靠谱客的博主 着急月饼,最近开发中收集的这篇文章主要介绍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的省略所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部