您好,欢迎访问一九零五行业门户网

SpringBoot中怎么通过自定义缓存注解实现数据库数据缓存到Redis

实现首先在mysql中新建一个表bus_student
然后基于此表使用代码生成,前端vue与后台各层代码生成并添加菜单。
然后来到后台代码中,在后台框架中已经添加了操作redis的相关依赖和工具类。
但是这里还需要添加aspect依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --><dependency> <groupid>org.springframework</groupid> <artifactid>spring-aspects</artifactid> <version>4.3.14.release</version> </dependency>
然后在存放配置类的地方新建新增redis缓存的注解
package com.ruoyi.system.redisaop;import java.lang.annotation.elementtype;import java.lang.annotation.retention;import java.lang.annotation.retentionpolicy;import java.lang.annotation.target;/* * @author * @description 新增redis缓存 **/@retention(retentionpolicy.runtime)@target(elementtype.method)public @interface aopcacheenable {//redis缓存key string[] key();//redis缓存存活时间默认值(可自定义)long expiretime() default 3600;}
以及删除redis缓存的注解
package com.ruoyi.system.redisaop;import java.lang.annotation.elementtype;import java.lang.annotation.retention;import java.lang.annotation.retentionpolicy;import java.lang.annotation.target;/* * @description 删除redis缓存注解 **/@target(elementtype.method)@retention(retentionpolicy.runtime)public @interface aopcacheevict {//redis中的key值 string[] key();}
然后再新建一个自定义缓存切面具体实现类cacheenableaspect
存放位置
package com.ruoyi.system.redisaop;import com.ruoyi.system.domain.busstudent;import org.aspectj.lang.proceedingjoinpoint;import org.aspectj.lang.signature;import org.aspectj.lang.annotation.around;import org.aspectj.lang.annotation.aspect;import org.aspectj.lang.annotation.pointcut;import org.aspectj.lang.reflect.methodsignature;import org.springframework.beans.factory.annotation.autowired;import org.springframework.data.redis.core.redistemplate;import org.springframework.stereotype.component;import java.lang.reflect.method;import java.util.arraylist;import java.util.list;import java.util.concurrent.timeunit;/* * @description 自定义缓存切面具体实现类 **/@aspect@componentpublic class cacheenableaspect { @autowiredpublic redistemplate rediscache;/** * mapper层切点 使用到了我们定义的 aopcacheenable 作为切点表达式。 */@pointcut("@annotation(com.ruoyi.system.redisaop.aopcacheenable)")public void querycache() { }/** * mapper层切点 使用到了我们定义的 aopcacheevict 作为切点表达式。 */@pointcut("@annotation(com.ruoyi.system.redisaop.aopcacheevict)")public void clearcache() { } @around("querycache()")public object interceptor(proceedingjoinpoint pjp) { object result = null;//注解中是否有#标识boolean spelflg = false;//判断是否需要走数据库查询boolean selectdb = false;//redis中缓存的keystring rediskey = "";//获取当前被切注解的方法名method method = getmethod(pjp);//获取当前被切方法的注解aopcacheenable aopcacheenable = method.getannotation(aopcacheenable.class);//获取方法参数值object[] arguments = pjp.getargs();//从注解中获取字符串string[] spels = aopcacheenable.key();for (string spe1l : spels) {if (spe1l.contains("#")) {//注解中包含#标识,则需要拼接spel字符串,返回redis的存储rediskeyrediskey = spe1l.substring(1) + arguments[0].tostring(); } else {//没有参数或者参数是list的方法,在缓存中的keyrediskey = spe1l; }//取出缓存中的数据result = rediscache.opsforvalue().get(rediskey);//缓存是空的,则需要重新查询数据库if (result == null || selectdb) {try { result = pjp.proceed();//从数据库查询到的结果不是空的if (result != null && result instanceof arraylist) {//将redis中缓存的结果转换成对象listlist<busstudent> students = (list<busstudent>) result;//判断方法里面的参数是不是busstudentif (arguments[0] instanceof busstudent) {//将rediskey-students 存入到redisrediscache.opsforvalue().set(rediskey, students, aopcacheenable.expiretime(), timeunit.seconds); } } } catch (throwable e) { e.printstacktrace(); } } }return result; }/*** 定义清除缓存逻辑,先操作数据库,后清除缓存*/@around(value = "clearcache()")public object evict(proceedingjoinpoint pjp) throws throwable {//redis中缓存的keymethod method = getmethod(pjp);// 获取方法的注解aopcacheevict cacheevict = method.getannotation(aopcacheevict.class);//先操作dbobject result = pjp.proceed();// 获取注解的key值string[] fieldkeys = cacheevict.key();for (string spe1l : fieldkeys) {//根据key从缓存中删除 rediscache.delete(spe1l); }return result; }/** * 获取被拦截方法对象 */public method getmethod(proceedingjoinpoint pjp) { signature signature = pjp.getsignature(); methodsignature methodsignature = (methodsignature) signature; method targetmethod = methodsignature.getmethod();return targetmethod; }}
注意这里的querycache和clearcache,里面切点表达式
分别对应上面自定义的两个aopcacheenable和aopcacheevict。
然后在环绕通知的querycache方法执行前后时
获取被切方法的参数,参数中的key,然后根据key去redis中去查询,
如果查不到,就把方法的返回结果转换成对象list,并存入到redis中,
如果能查到,则将结果返回。
然后找到这个表的查询方法,mapper层,比如要将查询的返回结果存储进redis
@aopcacheenable(key = "busstudent",expiretime = 40)public list<busstudent> selectbusstudentlist(busstudent busstudent);
然后在这个表的新增、编辑、删除的mapper方法上添加
/** * 新增学生 * * @param busstudent 学生 * @return 结果 */@aopcacheevict(key = "busstudent")public int insertbusstudent(busstudent busstudent);/** * 修改学生 * * @param busstudent 学生 * @return 结果 */@aopcacheevict(key = "busstudent")public int updatebusstudent(busstudent busstudent);/** * 删除学生 * * @param id 学生id * @return 结果 */@aopcacheevict(key = "busstudent")public int deletebusstudentbyid(integer id);
注意这里的注解上的key要和上面的查询的注解的key一致。
然后启动项目,如果启动时提示:
consider marking one of the beans as @primary, updating
the consumer to acce
因为sringboot通过@autowired注入接口的实现类时发现有多个,也就是有多个类继承了这个接口,spring容器不知道使用哪一个。
找到redis的配置类,在redistemplate上添加@primary注解
验证注解的使用
debug启动项目,在cacheenableaspect中查询注解中打断点,然后调用查询方法,
就可以看到能进断点,然后就可以根据自己想要的逻辑和效果进行修改注解。
以上就是springboot中怎么通过自定义缓存注解实现数据库数据缓存到redis的详细内容。
其它类似信息

推荐信息