缓存工具类编写
一般操作
在外面日常开发中,经常会有为了减少数据库压力,而将数据保存到缓存中并设置一个过期时间的操作。日常代码如下:
@Autowired
private RedisTemplate<String, String> redisTemplate;
public Object queryDataWithCache(String id) {
String cacheKey = "cacheKey:" + id;
String value = redisTemplate.opsForValue().get(cacheKey);
Object result = null;
if (ObjectUtil.isNotEmpty(value)) { // 缓存中存在数据,直接返回
result = JsonUtil.getJsonToList(value, Object.class); // 将字符串转换为对应的类型
} else { // 缓存中不存在数据,从数据库中查询
result = queryFromDB(id); // 从数据库中查询数据
String objectToString = JsonUtil.getObjectToString(result); // 将示例对象转换为json字符串
redisTemplate.opsForValue().set(cacheKey, objectToString, 10L, TimeUnit.SECONDS); // 将数据保存到缓存中
}
return result;
}
通过代码可以发现,从缓存中取数据,和把数据保存缓存中的逻辑都是通用的,只有从数据库查询数据是不同的,我们可以把缓存操作抽取出来作为一个工具类使用,减少重复代码的编写。
缓存工具类编写
import cn.hutool.core.util.ObjectUtil;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import tbea.util.JsonUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
/**
* @Description 本地缓存工具类
* @Author ZengXi
* @Date 2024/11/19
*/
@Component
public class CacheUtils<V>
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* @description: 获取数据
* @author ZengXi
* @date 2024/11/19
* @param cacheKey 缓存的key
* @param clazz 返回类型
* @param function 查询数据库操作的函数
* @param expireTime 缓存过期时间
* @return V
*/
public <V> V getResult(String cacheKey, Class<V> clazz, Supplier<V> function, int expireTime) {
V result = null;
String value = redisTemplate.opsForValue().get(cacheKey);
if (ObjectUtil.isNotEmpty(value)) {
result = JsonUtil.getJsonToBean(value, clazz);
} else {
result = function.get(); // 从数据库查询数据
if (ObjectUtil.isNotEmpty(result)) {
String objectToString = JsonUtil.getObjectToString(result);
redisTemplate.opsForValue().set(cacheKey, objectToString, expireTime, TimeUnit.SECONDS);
}
}
return result;
}
/**
* @description: 获取数据列表
* @author ZengXi
* @date 2024/11/19
* @param cacheKey 缓存的key
* @param clazz 返回列表元素的类型
* @param function 查询数据库操作的函数
* @param expireTime 缓存过期时间
* @return java.util.List<V>
*/
public List<V> getResultList(String cacheKey, Class<V> clazz, Supplier<List<V>> function,
int expireTime) {
String value = redisTemplate.opsForValue().get(cacheKey);
List<V> resultList = new ArrayList<>();
if (ObjectUtil.isNotEmpty(value)) {
resultList = JsonUtil.getJsonToList(value, clazz);
} else {
resultList = function.get(); // 从数据库查询数据
if (ObjectUtil.isNotEmpty(resultList)) {
String objectToString = JsonUtil.getObjectToString(resultList);
redisTemplate.opsForValue().set(cacheKey, objectToString, expireTime, TimeUnit.SECONDS);
}
}
return resultList;
}
}
工具类的使用
@Autowired
private CacheUtils cacheUtils;
public Object queryDataWithCache(String id) {
String cacheKey = "cacheKey:" + id;
Object result = cacheUtils.getResult(cacheKey, Object.class, () -> queryFromDB(id), 10);
return result;
}
总结
通过将查询数据库的函数作为传参,我们将缓存相关操作进行了抽取,减少了代码的编写,且如果后续需要更换缓存(如:将redis更换为把本地缓存),业务代码也不需要进行更改,只需要更改缓存工具类中的代码即可。