Spring与Redis的整合&&Redis注解式缓存以及Redis雪崩等问题的解决

目录

一、Spring整合Redis

二、Redis注解式缓存

        2.1 @Cacheable

        2.2 @CachePut

        2.3 @CacheEvict

三、Redis的击穿、穿透、以及雪崩问题

        Redis的运行过程

        3.1 击穿

        3.2 穿透

        3.3 雪崩


一、Spring整合Redis

首先我们要开启Redis服务

进入Redis的安装目录里

输入命令:./src/redis-service redis-conf

开始链接:./src/redis-cli -h 虚拟机IP -p 6379 -a 密码

整合步骤:

1、导入相关pom依赖;

2、修改pom依赖include中的jdbc.properties,把jdbc改为 * 号;

3、导入spring-redis.xml文件;

4、导入redis.properties文件;

5、在applicationContext.xml文件中添加外部多文件方式;

6、建立redis文件夹,导入指定生成规则文件CacheKeyGenerator.java;

【要在IDEA中下载Lombok插件】

Spring与Redis的整合&&Redis注解式缓存以及Redis雪崩等问题的解决_第1张图片  

 相关配置文件:

① 完整pom依赖:




    4.0.0

    org.example
    ssm
    1.0-SNAPSHOT
    war

    ssm Maven Webapp
    
    http://www.example.com

    
        UTF-8
        1.8
        1.8
        3.7.0

        
        
        5.0.2.RELEASE
        
        3.4.5
        
        5.1.44
        
        5.1.2
        
        1.3.1
        
        2.1.1
        2.4.3
        
        2.9.1
        
        4.12
        4.0.0
        1.18.2

        2.10.0
        1.7.7

        2.9.0
        1.7.1.RELEASE
    

    
        
        
            org.springframework
            spring-context
            ${spring.version}
        
        
            org.springframework
            spring-orm
            ${spring.version}
        
        
            org.springframework
            spring-tx
            ${spring.version}
        
        
            org.springframework
            spring-aspects
            ${spring.version}
        
        
            org.springframework
            spring-web
            ${spring.version}
        
        
            org.springframework
            spring-test
            ${spring.version}
        

        
        
            org.mybatis
            mybatis
            ${mybatis.version}
        
        
        
            mysql
            mysql-connector-java
            ${mysql.version}
        
        
        
            com.github.pagehelper
            pagehelper
            ${pagehelper.version}
        
        
        
            org.mybatis
            mybatis-spring
            ${mybatis.spring.version}
        

        
        
            org.apache.commons
            commons-dbcp2
            ${commons.dbcp2.version}
        
        
            org.apache.commons
            commons-pool2
            ${commons.pool2.version}
        

        
        
        
            org.apache.logging.log4j
            log4j-core
            ${log4j2.version}
        
        
            org.apache.logging.log4j
            log4j-api
            ${log4j2.version}
        
        
        
            org.apache.logging.log4j
            log4j-web
            ${log4j2.version}
        

        
        
            junit
            junit
            ${junit.version}
            test
        
        
            javax.servlet
            javax.servlet-api
            ${servlet.version}
            provided
        
        
            org.projectlombok
            lombok
            ${lombok.version}
            provided
        

        
            org.springframework
            spring-webmvc
            ${spring.version}
        

        
        
            javax.servlet.jsp
            javax.servlet.jsp-api
            2.3.3
        
        
            jstl
            jstl
            1.2
        
        
            taglibs
            standard
            1.1.2
        

        
            commons-fileupload
            commons-fileupload
            1.3.3
        

        
        
            org.hibernate
            hibernate-validator
            6.0.7.Final
        

        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.9.3
        
        
            com.fasterxml.jackson.core
            jackson-core
            2.9.3
        
        
            com.fasterxml.jackson.core
            jackson-annotations
            2.9.3
        

        
        
            org.apache.shiro
            shiro-core
            1.3.2
        

        
            org.apache.shiro
            shiro-web
            1.3.2
        

        
            org.apache.shiro
            shiro-spring
            1.3.2
        

        
            net.sf.ehcache
            ehcache
            ${ehcache.version}
        

        
        
            org.slf4j
            slf4j-api
            ${slf4j-api.version}
        
        
            org.slf4j
            jcl-over-slf4j
            ${slf4j-api.version}
            runtime
        

        
        
            org.apache.logging.log4j
            log4j-slf4j-impl
            ${log4j2.version}
        

        
            redis.clients
            jedis
            ${redis.version}
        
        
            org.springframework.data
            spring-data-redis
            ${redis.spring.version}
        
    

    
        ssm
        
            
            
                src/main/java
                
                    **/*.xml
                
            
            
            
                src/main/resources
                
                    *.properties
                    *.xml
                
            
        
        
            
                
                    org.apache.maven.plugins
                    maven-compiler-plugin
                    ${maven.compiler.plugin.version}
                    
                        ${maven.compiler.source}
                        ${maven.compiler.target}
                        ${project.build.sourceEncoding}
                    
                
                
                    org.mybatis.generator
                    mybatis-generator-maven-plugin
                    1.3.2
                    
                        
                        
                            mysql
                            mysql-connector-java
                            ${mysql.version}
                        
                    
                    
                        true
                    
                

                
                    maven-clean-plugin
                    3.1.0
                
                
                
                    maven-resources-plugin
                    3.0.2
                
                
                    maven-compiler-plugin
                    3.8.0
                
                
                    maven-surefire-plugin
                    2.22.1
                
                
                    maven-war-plugin
                    3.2.2
                
                
                    maven-install-plugin
                    2.5.2
                
                
                    maven-deploy-plugin
                    2.8.2
                
            
        
    

② spring-redis.xml




    
    

    
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

    
    
        
        
        
        
        
        
        
        
        
    

    
    
        
        
        
            
        
        
            
        
        
            
        
        
            
        
        
        
    

    
    
        
        
        
        
        
        
        
            
                
            
        
    

    
    

    
    

③ redis.properties 

redis.hostName=虚拟机IP
redis.port=6379
redis.password=链接密码
redis.timeout=10000
redis.maxIdle=300
redis.maxTotal=1000
redis.maxWaitMillis=1000
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.testOnBorrow=true
redis.testWhileIdle=true
redis.expiration=3600

④ applicationContext.xml 



    
    
    
        
        
        
            
                classpath:jdbc.properties
                classpath:redis.properties
            
        
    
    
    
    
    

⑤ CacheKeyGenerator.java 

package com.leaf.ssm.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Array;
import java.lang.reflect.Method;

@Slf4j
public class CacheKeyGenerator implements KeyGenerator {
    // custom cache key
    public static final int NO_PARAM_KEY = 0;
    public static final int NULL_PARAM_KEY = 53;

    @Override
    public Object generate(Object target, Method method, Object... params) {
        StringBuilder key = new StringBuilder();
        key.append(target.getClass().getSimpleName()).append(".").append(method.getName()).append(":");
        if (params.length == 0) {
            key.append(NO_PARAM_KEY);
        } else {
            int count = 0;
            for (Object param : params) {
                if (0 != count) {//参数之间用,进行分隔
                    key.append(',');
                }
                if (param == null) {
                    key.append(NULL_PARAM_KEY);
                } else if (ClassUtils.isPrimitiveArray(param.getClass())) {
                    int length = Array.getLength(param);
                    for (int i = 0; i < length; i++) {
                        key.append(Array.get(param, i));
                        key.append(',');
                    }
                } else if (ClassUtils.isPrimitiveOrWrapper(param.getClass()) || param instanceof String) {
                    key.append(param);
                } else {//Java一定要重写hashCode和eqauls
                    key.append(param.hashCode());
                }
                count++;
            }
        }

        String finalKey = key.toString();
//        IEDA要安装lombok插件
        log.debug("using cache key={}", finalKey);
        return finalKey;
    }
}

测试项目能够成功运行就OK啦!


二、Redis注解式缓存

2.1 @Cacheable

这个注解是配置在方法或类上的;

作用:

本方法执行后,先去缓存看有没有数据,如果没有,从数据库中查找出来,给缓存中存一份,最后返回结果;

等下次本方法执行,在缓存未过期情况下,先在缓存中查找,有的话直接返回,没有的话再从数据库查找。

测试代码:

@Cacheable(value = "user-bk",key = "'bk:'+#bid",condition = "#bid > 5") 
Book selectByPrimaryKey(Integer bid);

备注:

value:缓存位置的一段名称,不能为空

key:缓存的key,默认为空,表示使用方法的参数类型及参数值作为key,支持SpEL

condition:触发条件,满足条件就加入缓存,默认为空,表示全部都加入缓存,支持SpEL

我们编写一个测试类来测试调用两次方法试一下!

ClazzTest

package com.leaf.ssm;

import com.leaf.ssm.biz.BookBiz;
import com.leaf.ssm.biz.OrderBiz;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * @author Leaf
 * @site 2977819715
 * @company 玉渊工作室
 * @create  2022-10-27 15:23
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:applicationContext.xml"})
public class ClazzBizTest {
    @Autowired
    private BookBiz bookBiz;

    @Test
    public void test1(){
        System.out.println(bookBiz.selectByPrimaryKey(72));
        System.out.println(bookBiz.selectByPrimaryKey(72));
    }

    @Test
    public void test2(){
        bookBiz.deleteByPrimaryKey(72);
    }
}

测试结果:

Spring与Redis的整合&&Redis注解式缓存以及Redis雪崩等问题的解决_第2张图片

Spring与Redis的整合&&Redis注解式缓存以及Redis雪崩等问题的解决_第3张图片

再看看Redis客户端,是否真的存储了刚刚第一次调用方法查询到的数据:

Spring与Redis的整合&&Redis注解式缓存以及Redis雪崩等问题的解决_第4张图片

可以看到数据已缓存;

结论:

redis中有数据,则访问redis;如果没有数据,则访问MySQL;

由于后面两个注解缓存都是差不多的操作,就不花时间截图放运行结果了,统一放上测试代码和结论;

2.2 @CachePut

作用:

这个注解的话就是类似于更新操作,即每次不管缓存中有没有结果,都从数据库查找结果,并将结果更新到缓存,并返回结果!

测试代码:

@CachePut(value = "user-bk-put") 
Book selectByPrimaryKey(Integer bid);

结论:

这个就是只将数据库中查到的数据存储到缓存,不取缓存中的数据。(只存不取)

2.3 @CacheEvict

作用:

这个注解就是可以把之前我们用了存储缓存的地方的缓存清理掉;

测试代码:

//@CacheEvict(value = "user-bk-put",key = "'bk:'+#cid")//删除指定的缓存数据 
@CacheEvict(value = "user-bk-put",allEntries = true)//删除以 user-bk-put开头的缓存 
Book selectByPrimaryKey(Integer bid);

结论:

可以配置删除指定缓存数据,也可以删除符合规则的所有缓存数据;


三、Redis的击穿、穿透、以及雪崩问题

首先我们来明白一下Redis的运行过程:

Redis的运行机制就是后台查询的数据首先到达redis缓存区,看看是否有缓存,

如果没有、才会再去查询数据库,并且把查到的数据存储到redis缓存中,

如果下次再次查询到这条数据就直接从redis缓存中获取返回,以便提高性能;

3.1 击穿

什么是击穿:

就是面对高并发请求redis的某一个key值的时候,刚好这一个key失效,请求就直接击穿到数据库;

解决方案:

设置锁

1.获取 Redis 锁,如果没有获取到,则回到任务队列继续排队

2.获取到锁,从数据库拉取数据并放入缓存中

3.释放锁,其他请求从缓存中拿到数据

限流:请求redis之前做流量削峰

3.2 穿透

什么是穿透:

有时候一些高并发的请求数据压根就不存在,造成请求将缓存和数据库都穿透的情况。

解决方案:

规则排除

可以增加一些参数检验。例如数据库数据 id 一般都是递增的,如果请求 id = -10 这种参数,势必绕过Redis。 避免这种情况,可以对用户真实性检验等操作。

null值填充

当缓存穿透时,redis存入一个类似null的值,下次访问则直接缓存返回空, 当数据库中存在该数据的值则需要把redis存在的null值清除并载入新值;

此方案不能解决频繁随机不规则的key请求。

3.3 雪崩

什么是雪崩:

雪崩其实和击穿差不多,只不过击穿是高并发请求一条数据刚好失效,而雪崩是高并发访问的多条key数据同时失效,造成雪崩后果!

解决方案:

给不同的key数据设置不同的缓存策略。

你可能感兴趣的:(Spring,IDEA,redis,缓存,spring)