基于Redis通用缓存
redis简介:
流程:
基于Spring Aop切面类进行增强 ,逻辑如下
1.数据进入controller层调用service service调用对应dao方法进行查询前
应该先从redis中查询是否具有缓存, 如果有则从缓存中获取 (不需要去访问mysql增加压力)
如果没有缓存则执行目标方法(dao访问数据库获取数据) 获取到数据之后存储到redis中
2.缓存不应该不会清空,增删改之后都应该清除对应的缓存达到数据更新,避免出现增删改之后
返回给前端的数据还是缓存中的旧数据(脏读);
3.使用hash进行存储 可以存储key,value这样的话 key为
业务类类名
,value为方法名+实参列表
存入map集合的话就可以达到减少redis中存储条数过多
的问题;达到目的 具体实现如下:
- 创建切面类-->加入缓存
package com.wanshen.aspect;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;
import java.util.Set;
/**
* 集成redis缓存
*
* @author WanShen
* @date 2019年3月21日 16:30
*/
@Aspect//声明切面类
@Component //交给SpringBoot管理
@Slf4j //日志记录
public class CacheAspect {
@Autowired
private RedisTemplate redisTemplate;
/**
* 通知点+切入点 往redis中添加缓存
* key:方法名+实参列表
* className:类的全限定名
*
* @param point 织入点
* @return 返回需要的缓存对象
* @author WanShen
* @date 2019/3/21 16:32
*/
@Around("execution(* com.wanshen.service.YxCategoryService.query*(..))")
public Object addCache(ProceedingJoinPoint point) throws Throwable {
//获取操作对象
redisTemplate.setKeySerializer(new StringRedisSerializer());
//获取String类型操作对象
HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
//1.查询缓存前 先构建获取key的具体内容(key的设计为 业务类类名+方法名+实参列表)
StringBuilder stringBuilder = new StringBuilder();
//获取类名
String className = point.getTarget().getClass().getName();
//获取方法名
String methodName = point.getSignature().getName();
stringBuilder.append(methodName);
stringBuilder.append("-");
//获取实参列表
Object[] args = point.getArgs();
for (Object arg : args) {
stringBuilder.append(arg);
stringBuilder.append("-");
}
String key = stringBuilder.toString();
// 查询缓存中是否存在数据
Boolean cacheResult = hashOperations.hasKey(className, key);
Object result;
// 如果有的话直接获取缓存中的数据返回
if (cacheResult)
result = hashOperations.get(className, key);
else {
// 没有的话则查询 并且把结果存入redis缓存中
result = point.proceed();
hashOperations.put(className, key, result);
}
return result;
}
// 执行增删改之后缓存不一致应该删除
@AfterReturning("@annotation(com.wanshen.annocation.DelCache)")
public void delCache(JoinPoint joinpoint) {
// 获取当前目标方法类名
String className = joinpoint.getTarget().getClass().getName();
Set keys = redisTemplate.keys("*");
// 在redis中删除以className开头的数据
for (Object key : keys) {
if (key.toString().startsWith(className)) {
//删除对应key下的缓存数据
redisTemplate.delete(key);
}
}
}
}
缓存前后对比:
没有加入缓存前访问数据库 (图1)
加入缓存之后不访问数据库(图2)
- 清空缓存-->增删改方法使用
清空缓存操作对应于增删改之后再清空,这里使用自定义注解
package com.wanshen.annocation;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
//可以用在类和方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
public @interface DelCache {
}
原有切面类中加入delCache()方法 指定位置 在相关的位置上加入该注解
// 执行增删改之后缓存不一致应该删除
@AfterReturning("@annotation(com.wanshen.annocation.DelCache)")
public void delCache(JoinPoint joinpoint) {
// 获取当前目标方法类名
String className = joinpoint.getTarget().getClass().getName();
Set keys = redisTemplate.keys("*");
// 在redis中删除以className开头的数据
for (Object key : keys) {
if (key.toString().startsWith(className)) {
//删除对应key下的缓存数据
redisTemplate.delete(key);
}
}
}
标签:基于,缓存,Redis,redis,className,key,org,import
From: https://www.cnblogs.com/wanshen/p/17028766.html