首页 > 数据库 >基于Redis通用缓存

基于Redis通用缓存

时间:2023-01-05 20:23:04浏览次数:39  
标签:基于 缓存 Redis redis className key org import

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

标签:基于,缓存,Redis,redis,className,key,org,import
From: https://www.cnblogs.com/wanshen/p/17028766.html

相关文章

  • 电脑端钉钉部分数据缓存路径
    表情缓存:目录位置:%AppData%\Roaming\DingTalk\defEmotion头像缓存目录位置:%AppData%\DingTalk\xxxxx_v2\AvatarFiles聊天图片缓存目录位置:%AppData%\DingTalk\xxxxx......
  • Redis AOF持久化
    aof日志这种保存写操作命令到日志的持久化方式,就是Redis里的AOF(*AppendOnlyFile*)持久化功能,注意只会记录写操作命令,读操作命令是不会被记录的。在Redis中A......
  • Pomelo:网易开源基于 Node.js 的游戏服务端框架
    ​​Pomelo​​是基于Node.js的高性能、分布式游戏服务器框架。它包括基础的开发框架和相关的扩展组件(库和工具包),可以帮助你省去游戏开发枯燥中的重复劳动和底层逻辑......
  • 基于监控视频的汽车速度估计
    题目请研究如下问题:根据附件1中所提供的4秒钟夜间视频资料(包含74张连续图像)和附件2中标有1米间距线的现场图像,建立数学模型,估计该小车撞人时刻的速度。假设......
  • 基于libmemcached为php扩展memcached服务
    基于libmemcached,php扩展memcached的安装张映一,为什么要装memcached扩展memcached的1.2.4及以上增加了CAS(CheckandSet)协议,对于同一key的多进行程的并发处理问题。这......
  • cocos2d-x基于windows平台交叉编辑android工程
    cocos2d-x确实是一款优秀的引擎,尽管和正规军的unity3d比起来它显得有点土,但它在移动平台上的性能表现着实惊艳。以下讲解如何将win32工程交叉编译到android平台。 一、环境......
  • Adobe AIR for Android 缓存本地数据常用方法
    Local SharedObject这种方法比较简单方便的保存少的数据到到设备中。你不用自己去管理这些数据,设备会自动管理他。SharedObject 在 flash.net 包中,继承自EventDispatche......
  • 基于脚手架创建一个vue项目
    cd到项目想要创建到的地方vuecreatetest  ——创建一个名为test的vue项目   ——选择第三项(空格选择撤销回车下一项)   选择这两项  2.X版本......
  • 站酷基于服务网格ASM的生产实践
    作者:服务网格ASM背景介绍站酷(ZCOOL)2006年8月创立于北京,深耕设计领域多年,聚集了1500万设计师、摄影师、插画师、艺术家、创意人,在设计创意群体中具有一定的影响力与号召......
  • 基于开源体系的云原生微服务治理实践与探索
    作者:董艺荃|携程服务框架负责人携程微服务产品的发展历程携程微服务产品起步于2013年。最初,公司基于开源项目ServiceStack进行二次开发,推出.Net平台下的微服务框架CSe......