自定义注解与Redis结合加快查询速度

本文介绍了一种利用Redis缓存提高查询效率的方法。通过自定义注解与AOP结合,实现对特定Controller方法的缓存处理。文章详细解释了缓存机制、key生成策略及缓存更新流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 项目背景

        项目中有一些统计报表等等已经统计好的,不会变化的数据,需要展示给前端。这时,采用的方法是使用redis缓存json结果,加快查询速度。并且使用自定义注解作为切面,具体执行方法为切点,只要在具体需要缓存的Controller上面添加@CacheHandle注解即可。Redis里面存在数据的话去Redis缓存里面查找。否则去调用具体的执行方法到数据库查询。这种方法在于对代码的侵入性比较低,只用设计缓存的名称和失效策略,以及在需要缓存处理的方法上面加一个自定义的注解。

2. 源码介绍

   2.1 自定义注解类

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheHandle {

    public ACTION action() default ACTION.ADD;

    public SERVICE_NAME[] service_name() default {};

    public static enum SERVICE_NAME {
        OVERVIEW("overview"), INTERIOR("interior"), THIRD_PARTY("third_party");

        private String value;

        private SERVICE_NAME(String value) {
            this.value = value;
        }

        public String value() {
            return value;
        }
    }

    public static enum ACTION {
        ADD("add"), DELETE("delete");

        private String value;

        private ACTION(String value) {
            this.value = value;
        }

        public String value() {
            return value;
        }
    }
}

2.2 切面缓存处理类

/**
 * 缓存处理
 * 
 * @author licf
 */
@Component
@Aspect
public class CacheAspect implements Ordered {

    private Logger log = Logger.getLogger(CacheAspect.class);

    @Around("within(com.clickplus.controller..*) && @annotation(ccHandle))")
    public Object handleReq(ProceedingJoinPoint jp, CacheHandle ccHandle) throws Throwable {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
                .getRequest();
        long tenant_id = ((TenantUser) request.getSession().getAttribute(Constants.USER_INFO)).getTenantID()
                .longValue();
        if (CacheHandle.ACTION.ADD.value().equals(ccHandle.action().value())) {// 增加缓存
            Object[] objects = jp.getArgs();
            JSONObject json = null;
            for (int i = 0; i < objects.length; i++) {
                if (objects[i] instanceof JSONObject)
                    json = (JSONObject) objects[i];
            }
            CacheHandle.SERVICE_NAME temp = null;
            if (ccHandle.service_name().length == 1)
                temp = ccHandle.service_name()[0];
            if (temp != null) {
                String key = "dataCache_" + tenant_id + "_" + temp.value() + "_" + request.getRequestURI() + "_"
                        + EncryptionUtil.parseStrToMd5L32(JSON.toJSONString(json));
                String start_time = json.getString("start_time");
                String end_time = json.getString("end_time");
                Set<String> dateSet = null;
                try {
                    dateSet = DateUtil.getDateSet(start_time, end_time);
                } catch (Exception e) {
                    if (Constants.DEBUG)
                        e.printStackTrace();
                    return jp.proceed();
                }

                String today = DateUtil.date2String(new Date(), DateUtil.DEFAULT_DATE);
                if (dateSet.contains(today)) {
                    return jp.proceed();
                } else {
                    Object res = null;
                    JedisPool pool = null;
                    Jedis jedis = null;
                    try {
                        pool = RedisUtil.getInstance().getJedisPool();
                        jedis = pool.getResource();
                        String result = jedis.get(key);
                        if (result == null) {
                            res = jp.proceed();
                            // 方便测试
                            String temp_cache = String.valueOf(res);
                            if (res instanceof String) {
                                JSONObject o = JSON.parseObject(String.valueOf(res));
                                o.put("isCache", true);
                                temp_cache = JSON.toJSONString(o);
                            }
                            jedis.setex(key, 24 * 60 * 60, temp_cache);// 24小时
                            return res;
                        } else {
                            return result;
                        }
                    } catch (Exception e) {
                        if (Constants.DEBUG)
                            log.debug("RedisUtil执行方法报错", e);
                        if (res != null)
                            return res;
                        else
                            return jp.proceed();
                    } finally {
                        if (pool != null && jedis != null)
                            pool.returnResource(jedis);
                    }
                }
            } else {
                return jp.proceed();
            }
        } else if (CacheHandle.ACTION.DELETE.value().equals(ccHandle.action().value())) {

            CacheHandle.SERVICE_NAME[] temp = ccHandle.service_name();
            String[] keys = new String[temp.length];
            for (int j = 0; j < keys.length; j++) {
                keys[j] = "dataCache_" + tenant_id + "_" + temp[j].value() + "_*_*";
            }

            Object res = jp.proceed();
            JSONObject json = JSON.parseObject(String.valueOf(res));
            if (json.getBooleanValue("success")) {
                JedisPool pool = null;
                Jedis jedis = null;
                try {
                    pool = RedisUtil.getInstance().getJedisPool();
                    jedis = pool.getResource();
                    List<String> result = new ArrayList<String>();
                    for (int i = 0; i < keys.length; i++) {
                        result.addAll(jedis.keys(keys[i]));
                    }
                    if (result.size() > 0) {
                        String[] cache_keys = new String[result.size()];
                        cache_keys = result.toArray(cache_keys);
                        jedis.del(cache_keys);
                    }
                } catch (Exception e) {
                    if (Constants.DEBUG)
                        log.debug("RedisUtil执行方法报错", e);
                } finally {
                    if (pool != null && jedis != null)
                        pool.returnResource(jedis);
                }
            }
            return res;
        } else {
            return jp.proceed();
        }

    }

    @Override
    public int getOrder() {
        return 3;
    }

}

此处需要注意的是key的生成策略,一般以表名+登录用户ID + 接口名 +请求json的md5值,如下所示:

dataCache_3_interior_/ajax/interior_overview/get_terminal_overview_fa09c35f218fa7777cea8aac37b255ac

value值一般是json格式的返回结果。如果找到了直接返回给前端页面,没找到或者出错,则添加到缓存。具体一些key的生成策略可以根据实际选用。

还可以参考自定义注解与AOP,Redis的结合


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值