【Redis】整合使用,进行注解式开发及应用场景和击穿、穿透、雪崩的讲解

目录

一、整合

1. 为什么

2. 整合应用

( 1 ) pom配置

( 2 ) 所需配置

3. 注解式开发及应用场景

1. @Cacheable

2. @CachePut

3. @CacheEvict

4. 击穿、穿透、雪崩


一、整合

1. 为什么

Redis可以与SSM项目整合,主要是为了提高项目的性能和效率。以下是整合Redis对项目开发的好处:

1. 缓存数据:Redis作为内存数据库,可以将常用的数据存储在内存中,以提高数据的读取速度。通过缓存数据,可以减少对数据库的访问次数,从而提高系统的响应速度。

2. 高性能缓存:Redis是一种基于内存的高性能缓存数据库,通过将常用的数据存储在内存中,可以大大提高数据的读取速度。在SSM项目中,可以将频繁访问的数据存储在Redis中,减少对数据库的访问次数,从而提高系统的响应速度和性能。

3. 分布式锁:在分布式环境中,多个节点同时访问共享资源可能会导致数据冲突和并发问题。Redis提供了分布式锁的功能,可以保证在同一时刻只有一个线程可以访问共享资源,避免数据的冲突和并发问题。

4. 消息队列:Redis支持发布/订阅模式和消息队列功能,可以用于解耦系统的各个模块,实现异步处理和消息传递。通过使用Redis的消息队列,可以提高系统的可扩展性和可靠性。

5. 计数器和排行榜:Redis提供了计数器和有序集合的功能,可以用于实现各种统计和排行榜功能。在SSM项目中,可以利用Redis的计数器和排行榜功能,方便地统计数据和展示排名,提升用户体验和系统的功能性。

6. 分布式缓存:通过将Redis部署在多台服务器上,可以实现分布式缓存,提高系统的可用性和容错性。通过使用分布式缓存,可以将数据分散存储在不同的服务器上,避免单点故障和数据丢失的风险

综上所述,整合Redis可以提升SSM项目的性能、并发处理能力、可扩展性和可靠性,从而提高系统的用户体验和功能性。

2. 整合应用

( 1 ) pom配置

在项目的 pom.xml 文件中添加Redis的依赖

 以下是导入的所有依赖 : 




  4.0.0

  org.example
  ssm2
  1.0-SNAPSHOT
  war

  ssm2 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}
    
  

  
    ssm2
    
      
      
        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
        
      
    
  

注意

在引入Redis的依赖时,需要注意以下几点:

1. 版本兼容性:确保所引入的Redis依赖与项目的其他依赖库相兼容。不同版本的Redis依赖可能会有不同的功能和API,因此需要根据项目的实际情况选择合适的版本。

2. 依赖冲突:检查项目的依赖关系,避免与Redis依赖存在冲突。如果项目中已经引入了其他与Redis相关的库,如Jedis或Lettuce等,需要确认它们与所引入的Redis依赖是否兼容,避免冲突。

3. Maven坐标:确保在pom.xml文件中正确地添加Redis的依赖坐标。可以通过访问Maven中央仓库或Redis官方网站获取最新的依赖坐标。

4. 依赖更新:定期检查Redis依赖的更新情况,以获取最新的功能和修复的bug。Redis社区会不断更新和改进Redis的版本,因此及时更新依赖可以提高项目的性能和安全性。

5. 依赖管理工具:根据项目的需要,可以选择使用不同的依赖管理工具,如Maven或Gradle。确保在使用相应工具时正确配置Redis的依赖。

通过注意以上几点,可以确保引入Redis的依赖时避免出现版本冲突、依赖错误等问题,从而顺利地进行Redis与SSM项目的整合。

( 2 ) 所需配置

在SSM项目中创建一个 spring-readis.xml,配置Redis连接信息,配置数据源,配置序列化器及redis的key生成策略,配置RedisTemplate。

创建 redis.properties 进行编写数据连接的信息,包括主机名、端口号、密码等。

redis.hostName=localhost
redis.port=6379
redis.password=123456
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

 创建 spring-redis.xml 配置文件,在其中配置以下

redis连接池的配置

 
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

配置redis连接工厂

    
    
        
        
        
        
        
        
        
        
        
    

redis操作模板

    
    
        
        
        
            
        
        
            
        
        
            
        
        
            
        
        
        
    

配置缓存管理器

    
    
        
        
        
        
        
        
        
            
                
            
        
    

创建 CacheKeyGenerator.java 配置缓存生成键名的生成规则

package com.CloudJun.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;
    }
}

最后 spring-redis.xml 配置文件的所有配置如下 : 




    
    

    
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
        
    

    
    
        
        
        
        
        
        
        
        
        
    

    
    
        
        
        
            
        
        
            
        
        
            
        
        
            
        
        
        
    

    
    
        
        
        
        
        
        
        
            
                
            
        
    

    
    

    
    

创建 applicationContext-shiro.xml 配置文件 




    
    
        
        
        
        
        
        
            
                
                
                
                
                
                
            
        
    

    
    
        
        
    

    
    
        
        
        
        
        
        
        
        
        
        
            
                
                
                
                
                /user/login=anon
                /user/updatePwd.jsp=authc
                /admin/*.jsp=roles[4]
                /user/teacher.jsp=perms[2]
                
            
        
    

    
    


    
    
    

    
    
        
    

    
    

    
    
        
        
        
        
        
        
    

    
    
        
        
        
        
        
        
        
        
        
        
        
        
        
        
            
                
            
        
        
        
        
        
    

在引用的配置文件中引用以上配置的文件 如 applicationContext.xml



    
    
        
        
        
            
                classpath:jdbc.properties
                classpath:redis.properties
            
        
    


    
    
    

以上是基本的配置步骤,根据具体的项目需求和框架版本可能会有所不同。在实际应用中,还可以根据需要配置Redis的集群、哨兵模式、持久化等功能,以提高系统的可用性和可靠性。

3. 注解式开发及应用场景

1. @Cacheable

@Cacheable是Spring框架提供的一个缓存注解,用于标记方法的返回结果可以被缓存起来,以提高系统的性能。

具体来说,@Cacheable注解的作用如下:

1. 缓存结果:当一个被@Cacheable注解修饰的方法被调用时,Spring会先检查缓存中是否存在该方法的返回结果。如果缓存中已经存在,则直接返回缓存中的结果,而不再执行方法体内的代码逻辑。

2. 缓存键生成:@Cacheable注解可以指定一个缓存键(key)来标识缓存中的数据。默认情况下,缓存键是由方法的参数组成的。如果两次调用的方法参数相同,则会使用相同的缓存键,从而直接返回缓存中的结果。

3. 缓存管理:@Cacheable注解可以与其他缓存管理工具(如Redis、Ehcache等)进行整合使用。通过在配置文件中配置相应的缓存管理器,可以将方法的返回结果存储到指定的缓存中,以供后续的调用使用。

4. 缓存失效:@Cacheable注解还可以指定一个失效时间(TTL)来控制缓存的有效期。当缓存的有效期过期后,下一次调用该方法时会重新执行方法体内的代码逻辑,并将新的结果存储到缓存中。

使用@Cacheable注解可以有效地减少对数据库或其他资源的访问次数,提高系统的响应速度和并发处理能力。但需要注意的是,使用缓存时需要权衡缓存的一致性和实时性,避免数据不一致或过期的问题。

常用属性及用法作用

@Cacheable注解有以下常用属性及用法作用:

  1. value:指定缓存的名称,用于区分不同的缓存空间。可以在配置文件中配置相应的缓存管理器,以决定将缓存存储在哪个缓存空间中。可以指定多个缓存名称,使用逗号分隔。

  2. key:指定缓存的键,用于标识缓存中的数据。默认情况下,缓存键是由方法的参数组成的。可以使用SpEL表达式来指定缓存键,例如:@Cacheable(key = "#id"),其中id是方法的参数。

  3. condition:指定一个SpEL表达式,用于判断是否执行缓存操作。只有当表达式的结果为true时,才会执行缓存操作。例如:@Cacheable(condition = "#result != null"),表示只有当方法的返回结果不为空时,才会执行缓存操作。

  4. unless:指定一个SpEL表达式,用于判断是否不执行缓存操作。只有当表达式的结果为false时,才会执行缓存操作。例如:@Cacheable(unless = "#result == null"),表示只有当方法的返回结果为空时,才不会执行缓存操作。

  5. keyGenerator:指定一个自定义的缓存键生成器,用于生成缓存的键。可以实现KeyGenerator接口来自定义缓存键的生成逻辑。

使用@Cacheable注解可以将方法的返回结果缓存起来,提高系统的响应速度和并发处理能力。通过指定缓存名称、缓存键、条件和键生成器等属性,可以对缓存进行更加精细的控制。同时,需要注意权衡缓存的一致性和实时性,避免数据不一致或过期的问题。

2. @CachePut

@CachePut是Spring框架提供的一个缓存注解,用于标记方法执行后更新缓存中的数据。

具体来说,@CachePut注解的作用如下:

1. 更新缓存:当一个被@CachePut注解修饰的方法被调用时,Spring会执行方法体内的代码逻辑,并更新缓存中与该方法相关的数据。可以通过指定缓存键(key)来更新指定的缓存数据,或者通过指定allEntries=true来更新所有缓存数据。

2. 缓存键生成:与@Cacheable注解类似,@CachePut注解也可以指定一个缓存键(key)来标识缓存中的数据。默认情况下,缓存键是由方法的参数组成的。

3. 缓存管理:@CachePut注解同样可以与其他缓存管理工具(如Redis、Ehcache等)进行整合使用。通过在配置文件中配置相应的缓存管理器,可以更新指定缓存中的数据。

使用@CachePut注解可以在方法执行后更新缓存中的数据,适用于需要更新缓存数据的场景。通过指定缓存键或设置allEntries=true,可以更新指定的缓存数据或更新所有缓存数据。因此,@CachePut注解常用于需要保持缓存数据与实际数据一致性的方法,以避免脏数据或过期数据的问题。

@CachePut的常用属性及用法作用和@Cacheable的常用属性及用法作用是一样的并且作用也相同,都是Spring框架提供的缓存注解,但在作用上有一些区别。

1. 功能区别:

  • @Cacheable注解用于标记方法的返回结果应该被缓存,当相同的方法被再次调用时,会直接从缓存中获取结果,而不会执行方法体内的代码逻辑。
  • @CachePut注解用于标记方法执行后更新缓存中的数据,即使缓存中已存在相同的键值对,也会强制更新缓存数据。

2. 使用场景区别:

  • @Cacheable适用于读取频繁,但不经常更新的数据。例如,查询数据库中的静态数据或配置信息。
  • @CachePut适用于需要频繁更新缓存数据的场景。例如,写入数据库的操作,每次写入后都需要更新缓存中的数据。

3. 缓存键的生成方式:

  • @Cacheable默认使用方法的参数作为缓存键,可以通过指定key属性来自定义缓存键的生成方式。
  • @CachePut同样默认使用方法的参数作为缓存键,也可以通过指定key属性来自定义缓存键的生成方式。

总体来说,@Cacheable注解用于读取缓存数据,而@CachePut注解用于更新缓存数据。在使用时,需要根据实际的业务需求来选择合适的注解。有时候,两者也可以结合使用,以实现更加灵活的缓存操作。

3. @CacheEvict

@CacheEvict是Spring框架提供的一个缓存注解,用于标记方法执行后清除缓存中的数据。

作用和@CachePut注解及@Cacheable注解都大同小异。

常用属性及用法作用

@CacheEvict注解有以下几个常用的属性:

  • 1. value:指定要操作的缓存名称,可以是一个字符串数组,用于指定多个缓存名称。
  • 2. key:指定缓存的键,可以使用SpEL表达式来动态生成缓存键。
  • 3. condition:指定一个SpEL表达式,当条件为true时才会执行缓存移除操作。
  • 4. allEntries:一个布尔值,用于指定是否移除指定缓存中的所有数据。默认为false,表示只移除指定键对应的缓存数据。
  • 5. beforeInvocation:一个布尔值,用于指定缓存移除操作是在方法执行前还是执行后进行。默认为false,表示在方法执行后进行缓存移除操作。

@CacheEvict的作用是从缓存中移除数据。通过指定缓存名称、缓存键、条件等属性,可以对缓存进行更加精细的控制。常见的用法包括:

1. 移除指定缓存中的指定键的数据:

@CacheEvict(value = "myCache", key = "#id")
public void deleteData(String id) {
    // 删除数据的逻辑
}

2. 移除指定缓存中的所有数据:

@CacheEvict(value = "myCache", allEntries = true)
public void clearCache() {
    // 清除缓存的逻辑
}

3. 根据条件移除缓存数据:

@CacheEvict(value = "myCache", condition = "#result > 0")
public int updateData(String id) {
    // 更新数据的逻辑
    return updatedRows;
}

需要注意的是,@CacheEvict注解通常用于更新缓存数据或在删除数据时同步移除缓存数据,因此建议在方法执行后进行缓存移除操作(即beforeInvocation属性设置为false)。这样可以避免在方法执行过程中出现异常导致缓存数据未正确移除的问题。

功能

  • @CacheEvict注解用于标记方法执行后从缓存中移除数据。它可以在方法执行前或执行后移除缓存数据。

使用场景

  • @CacheEvict适用于需要从缓存中移除数据的场景。例如,删除数据库中的数据后,需要同时从缓存中移除对应的数据。

缓存键的生成方式

  • @CacheEvict默认使用方法的参数作为缓存键,可以通过指定key属性来自定义缓存键的生成方式。

4. 击穿、穿透、雪崩

缓存中常见的三种现象:击穿、穿透、雪崩。

1. 击穿

当缓存中不存在某个key的数据,而有大量并发请求访问这个key时,这些请求会直接穿过缓存,去访问数据库,导致数据库压力过大,甚至宕机。这种现象称为“击穿”。

解决方法:

使用互斥锁或分布式锁,保证只有一个线程去访问数据库,其他线程等待结果即可。

2. 穿透

当某个key对应的数据在缓存中不存在,而且这个key被大量请求访问时,这些请求会直接访问数据库,导致数据库压力过大,甚至宕机。这种现象称为“穿透”。

解决方法:

在缓存中预先设置这个key对应的空值或默认值,避免大量请求直接访问数据库。

3. 雪崩

当缓存中的大量数据同时失效,而且这些数据被大量请求访问时,这些请求会直接访问数据库,导致数据库压力过大,甚至宕机。这种现象称为“雪崩”。

解决方法:

  • - 缓存数据的失效时间设置随机,避免大量数据同时失效。
  • - 使用多级缓存架构,避免单点故障。
  • - 使用熔断机制,当缓存失效时,暂时屏蔽对数据库的访问,避免压力过大。

以上三种现象都是缓存中常见的问题,需要在缓存的设计和使用中予以考虑和解决。

你可能感兴趣的:(redis,数据库,缓存,运维,linux,java)