基于Redis通用缓存

基于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)

图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);
            }
        }
    }
posted @ 2023-01-05 20:08  万神·  阅读(74)  评论(0编辑  收藏  举报