redis做方法缓存

redis做方法缓存

为什么要拿redis做缓存?

​ redis是一个完全基于内存、数据结构简单、采用单线程的工作方式(避免了不必要的上下文切换)、使用IO多路复用的一个key-value类型的数据库。查询速度要远比mysql这种关系型数据库要快得多。

​ 系统绝大多数场景下都是读多写少,而mysql能够承受的并发量在每秒两三千(百度得到的数据)的时候就会面临宕机的风险了,并且查询速度极慢。

1、查询流程

​ 在请求达到后端之后,对需要进行缓存的接口,会先去redis中找有无数据,没有的话会继续走正常的业务流程,然后将查询到的结果返回给客户端的同时也放在redis中一份,下次相同请求进来后,就可以直接从redis中拿到数据。

在这里插入图片描述

2、代码实现,举个栗子

2.1 自定义缓存注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface RedisCache {
    int expire() default 86400;//缓存多少秒,默认 24*60*60 1天
    String key() default "";//缓存key为空时取方法名
}
2.2 对添加@RedisCache注解的方法进行缓存
@SuppressWarnings("unchecked")
@Around("@annotation(com.shao.cacheCompont.RedisCache)")
public Object RedisCache(final ProceedingJoinPoint jp) throws Throwable {

    Method method = getMethod(jp);//获取注解上的方法
    RedisCache cache = method.getAnnotation(RedisCache.class);
    final String cacheKey = cache.key();
    StringBuilder buf = new StringBuilder();
    if (StringUtil.isNotBlank(cacheKey)) {
        buf.append(cacheKey);
    } else {
        buf.append(jp.getSignature().getDeclaringTypeName()).append(".").append(jp.getSignature().getName());
    }
    Object[] args = jp.getArgs();
    String key = "";
    if (args == null || args.length == 0) {
        key = buf.toString();
    } else {
        key = buf.append(".").append(JSON.toJSONString(args)).toString();
    }
    //!!!注意这里的HttpResult.class这里为我的controller的统一响应类型
    Object o = JSON.parseObject((String) redisTemplate.opsForValue().get(key), HttpResult.class);
    Object result = null;
    if (null == o) {
        result = jp.proceed(args);//缓存中查询不到则继续执行方法体
        final int expire = cache.expire();
        redisTemplate.opsForValue().set(key,JSON.toJSONString(result), expire, TimeUnit.SECONDS);
        return result;
    } else {
        return o;//缓存中查询到结果则直接返回
    }
}
private Method getMethod(ProceedingJoinPoint jp) {
        
    MethodSignature signature = (MethodSignature) jp.getSignature();
    Method runningMethod = signature.getMethod();
    Class<?>[] parameterTypes = runningMethod.getParameterTypes();
    Method method = null;
    try {
        method = jp.getTarget().getClass().getMethod(jp.getSignature().getName(), parameterTypes);
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    }
    return method;
}
2.3 使用
/**
* 功能描述: 查询所有影片
*/
@PostMapping("/selectAllFilm")
@RedisCache
//这里添加注解,对该接口进行缓存(注意这里的返回类型【HttpResult】要和缓存方法中的类型保持一致,否则会出类型转换问题)
public HttpResult selectAllFilm(@RequestBody SearchFilmVOSearch filmVO) {
    PageInfo pageInfo = filmService.searchAllFilm(filmVO);
    return HttpResult.ok(pageInfo);
}
2.4 测试

第一次请求该接口时,数据并没有加入缓存中,我们可以看到请求耗时为303ms

在这里插入图片描述

第二次请求,可以明显看到时间大大缩短到了9ms,响应速度提升了三十倍

在这里插入图片描述

3、数据同步问题

​ 在进行缓存之后,相同的请求在缓存时间内是不会去读取数据库的,但是此时如果修改了数据库,则接口返回的数据就不能保证和数据库一致,因此在增、删、改时我们需要刷新缓存。

3.1 自定义刷新缓存注解,在增删改方法上添加该注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface UpdateCache {
    
    /** 指定要刷新的key,可以进行模糊匹配 */
    String key() default "";
}
3.2 在有@UpdateCache注解的方法上会刷新本类下的所有缓存
@Around("@annotation(com.shao.cacheCompont.UpdateCache)")
public Object UpdateCache(final ProceedingJoinPoint jp) throws Throwable {

    Method method = getMethod(jp);
    UpdateCache annotation = method.getAnnotation(UpdateCache.class);
    final String cacheKey = annotation.key();
    StringBuilder buf = new StringBuilder();
    if (StringUtil.isNotBlank(cacheKey)) {
        buf.append(cacheKey);
    } else {
        buf.append(jp.getSignature().getDeclaringTypeName()).append(".").append("*");
    }
    String key = buf.toString();
    Set<String> keys = redisTemplate.keys(key);
    if (keys != null && keys.size() != 0) {
        keys.forEach(k->{
            redisUtils.del(k);
        });
    }
    return jp.proceed(jp.getArgs());
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个小白QAQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值