使用Redis实现切成编程操作

本文详细介绍如何在SpringBoot项目中使用自定义注解和AOP切面编程实现Redis缓存,包括定义注解、使用注解及AOP切面的具体实现。同时,介绍了Redis的基本数据类型及其特点,以及Redis快速响应的原因。
摘要由CSDN通过智能技术生成
此工程为Spring boot项目
Redis切成编程

目标:在方法上添加一个注解,实现查询的时候缓存

方法:自定义注解+AOP切面编程

步骤

话不多说,直接上代码演示

第一步

定义注解

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

    //存储前缀
    String name() default "Spl---";

    //要存储的key,默认是查询条件的第一个参数
    String key() default "";

    //默认5分钟
    int expireTime() default 5;

    //默认值是以分钟为单位
    TimeUnit unit() default TimeUnit.MINUTES;
}
第二步

注解使用的地方
在这里插入图片描述

第三步

AOP切面思想

@Component
@Aspect
@Slf4j
/**
 * AOP切面编程
 */
public class RedisCacheAop {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 切入点
     */
    @Pointcut("@annotation(com.trc.study.annotation.RedisCache)")
    public void pointCup(){}

    /**
     * 增强方法-环绕
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around(value = "pointCup()")
    public Object cache(ProceedingJoinPoint joinPoint) throws Throwable{
        //从切入点,获取方法签名
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        //从切点,获取目标对象的字节码,的方法。参数:(方法名,方法的所有参数)
        RedisCache redisCache = method.getAnnotation(RedisCache.class);
        String key = redisCache.key();
        Object[] args = joinPoint.getArgs();
        String prefix = redisCache.name();
        String methodName = method.getName();
        //获取key值
        String cacheKey = getCacheKey(key, args, prefix, methodName);

        Object proceed = null;
        //根据key从缓存获取值
        String value = stringRedisTemplate.opsForValue().get(cacheKey);
        //判断value是否为空
        if (StringUtils.isNotBlank(value)){
            log.info("从redis里面获取数据!");
            return getValueActualTypeData(method,value);
        }else {
            log.info("从mysql里面获取数据!");
            //查询数据库,执行原来的方法
            proceed = joinPoint.proceed();
            //封装结果
            String results = JSONObject.toJSONString(proceed);
            int expireTime = redisCache.expireTime();
            TimeUnit timeUnit = redisCache.unit();
            //存入缓存
            stringRedisTemplate.opsForValue().set(cacheKey,results,expireTime,timeUnit);
            return proceed;
        }
    }

    /**
     *  获取key值
     * @param key
     * @param args
     * @param prefix
     * @param methodName
     * @return
     */
    private String getCacheKey(String key,Object[] args,String prefix,String methodName){
        String cacheKey = "";
        if (StringUtils.isNotBlank(prefix)) {
            cacheKey = "/" + prefix + "/";
        }
        if (StringUtils.isNotBlank(key)) {
            return cacheKey += key;
        }
        if (null != args && 0 < args.length) {
            return cacheKey += args[0];
        }
        return methodName;
    }

    /**
     * 获取数据
     * @param method
     * @param value
     * @return
     * @throws ClassNotFoundException
     */
    private Object getValueActualTypeData(Method method, String value) throws ClassNotFoundException {
        Class returnActualType = getReturnActualType(method);
        if (null != returnActualType) {
            return JSONObject.parseArray(value, returnActualType);
        }
        return null;
    }
    /**
     * 获取返回值类型
     * @param method
     * @return
     * @throws ClassNotFoundException
     */
    private Class getReturnActualType(Method method) throws ClassNotFoundException {
        Type genericReturnType = method.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType) {
            Type[] actualTypes = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualType : actualTypes) {
                return Class.forName(actualType.getTypeName());
            }
        }
        return null;
    }
    
}

其他:工程结构
mvc模式
在这里插入图片描述
配置文件

server.port=9009
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
spring.datasource.username=root
spring.datasource.password=root
mybatis.type-aliases-package=com.trc.study.common
mapper.mappers=com.trc.study.dao.RedisCacheMapper

logging.level.info
#redis配置
#Redis服务器地址
spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379
#Redis数据库索引(默认为0)
spring.redis.database=0
#连接池最大连接数(使用负值表示没有限制)
spring.redis.jedis.pool.max-active=50
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.jedis.pool.max-wait=3000
#连接池中的最大空闲连接
spring.redis.jedis.pool.max-idle=20
#连接池中的最小空闲连接
spring.redis.jedis.pool.min-idle=2
#连接超时时间(毫秒)
spring.redis.timeout=5000


redis基本数据类型
数据类型
	String: 字符串
		可以用来存储字符串、整数、浮点数
		缓存
		数据共享分布式
		分布式锁
		全局ID
		计数器
		限流
	Hash: 散列
		包含键值对的无序散列表。value只能是字符串,不能嵌套其他类型
		存储对象类型的数据
	List: 列表
		存储有序的字符串(从左到右),元素可以重复。可以充当队列和栈的角色
		用户消息时间线timeline
	Set: 集合
		String类型的无序集合,最大存储数量2^32-1(40亿左右)
		随机获取元素
	ZSet: 有序集合
		sorted set,有序的set,每个元素有个score。
		score相同时,按照key的ASCII码排序。
	BitMaps
		是在字符串类型上面定义的位操作。一个字节由8个二进制位组成。
	Hyperloglogs
		提供了一种不太准确的基数统计方法
	Streams
		5.0推出的数据类型。支持多播的可持久化的消息队列,用于实现发布订阅功能
Redis 为什么这么快
1)纯内存结构
	KV结构的内存数据库,时间复杂度O(1)
2)单线程
	1、没有创建线程、销毁线程带来的消耗
	2、避免了上线文切换导致的CPU消耗
	3、避免了线程之间带来的竞争问题,例如加锁释放锁死锁等等
3)多路复用
	“多路”指的是多个网络连接,“复用”指的是复用同一个线程
	利用select、poll、epoll可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有I/O事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll是只轮询那些真正发出了事件的流),依次顺序的处理就绪的流,这种做法就避免了大量的无用操作
主从、哨兵
集群
	可用性、数据安全、性能
主从
	从节点不能写入数据(只读),只能从 master 节点同步数据
	主从复制原理
		连接阶段
		 数据同步阶段
		命令传播阶段
	不足
		RDB文件过大的情况下,同步非常耗时
		如果主服务器挂了,对外提供的服务就不可用
哨兵
	通过运行监控服务器来保证服务的可用性
		会对Sentinel做集群的部署。Sentinel既监控所有的Redis服务,Sentinel之间也相互监控
	通信
		SDOWN与ODOWN转换过程
		Sentinel与slaves"自动发现"机制
		Leader选举
分布式方案
	Redis数据的分片
		在客户端实现相关的逻辑,例如用取模或者一致性哈希对key进行分片,查询和修改都先判断key的路由
		把做分片处理的逻辑抽取出来,运行一个独立的代理服务,客户端连接到这个代理服务,代理服务做请求的转发
		基于服务端实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值