目录
一.整合
1.1.整合应用
1.1.1.pom配置
1.1.2.所需配置
二.注解式开发及应用场景
2.1. @Cacheable
2.2. @CachePut
2.3. @CacheEvict
2.4.总结
三.redis的击穿穿透雪崩
好啦今天就到这里了哦!!希望能帮到你哦!!
在项目的 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.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
在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.junlinyi.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的集群、哨兵模式、持久化等功能,以提高系统的可用性和可靠性。
@Cacheable是Spring Framework中的一个注解,用于声明方法的返回值是可以被缓存的。这意味着方法的返回值将被缓存在内存中,以便之后的调用可以直接返回缓存的结果,而无需再次执行该方法。
具体来说,@Cacheable注解的作用如下:
1. 缓存结果:当一个被@Cacheable注解修饰的方法被调用时,Spring会先检查缓存中是否存在该方法的返回结果。如果缓存中已经存在,则直接返回缓存中的结果,而不再执行方法体内的代码逻辑。
2. 缓存键生成:@Cacheable注解可以指定一个缓存键(key)来标识缓存中的数据。默认情况下,缓存键是由方法的参数组成的。如果两次调用的方法参数相同,则会使用相同的缓存键,从而直接返回缓存中的结果。
3. 缓存管理:@Cacheable注解可以与其他缓存管理工具(如Redis、Ehcache等)进行整合使用。通过在配置文件中配置相应的缓存管理器,可以将方法的返回结果存储到指定的缓存中,以供后续的调用使用。
4. 缓存失效:@Cacheable注解还可以指定一个失效时间(TTL)来控制缓存的有效期。当缓存的有效期过期后,下一次调用该方法时会重新执行方法体内的代码逻辑,并将新的结果存储到缓存中。
使用@Cacheable注解可以有效地减少对数据库或其他资源的访问次数,提高系统的响应速度和并发处理能力。但需要注意的是,使用缓存时需要权衡缓存的一致性和实时性,避免数据不一致或过期的问题。
常用属性及用法作用
@Cacheable注解有以下常用属性及用法作用:
value:指定缓存的名称,用于区分不同的缓存空间。可以在配置文件中配置相应的缓存管理器,以决定将缓存存储在哪个缓存空间中。可以指定多个缓存名称,使用逗号分隔。
key:指定缓存的键,用于标识缓存中的数据。默认情况下,缓存键是由方法的参数组成的。可以使用SpEL表达式来指定缓存键,例如:@Cacheable(key = "#id"),其中id是方法的参数。
condition:指定一个SpEL表达式,用于判断是否执行缓存操作。只有当表达式的结果为true时,才会执行缓存操作。例如:@Cacheable(condition = "#result != null"),表示只有当方法的返回结果不为空时,才会执行缓存操作。
unless:指定一个SpEL表达式,用于判断是否不执行缓存操作。只有当表达式的结果为false时,才会执行缓存操作。例如:@Cacheable(unless = "#result == null"),表示只有当方法的返回结果为空时,才不会执行缓存操作。
keyGenerator:指定一个自定义的缓存键生成器,用于生成缓存的键。可以实现KeyGenerator接口来自定义缓存键的生成逻辑。
使用@Cacheable注解可以将方法的返回结果缓存起来,提高系统的响应速度和并发处理能力。通过指定缓存名称、缓存键、条件和键生成器等属性,可以对缓存进行更加精细的控制。同时,需要注意权衡缓存的一致性和实时性,避免数据不一致或过期的问题。
基本用法示例:
@Cacheable(value = "clz" ,key = "'cid'+#cid")
用法内属性解释:
- value: 用于指定缓存的名称,你可以在配置文件中定义不同的缓存管理器,这里的"value"指定了要使用的缓存。
- key属性:使用SpEL表达式,"'cid'+#cid"生成缓存的键。这个键将由方法的cid参数的值动态生成。如果方法被调用时传入不同的cid值,将会生成不同的缓存键,因此不同的cid值将会对应不同的缓存项。这允许你在不同的上下文中存储和获取缓存数据。
@CachePut
是 Spring Framework 中的一个注解,用于将方法的返回值存储到缓存中,通常用于更新缓存中的数据。
@CachePut方法作用:
- 更新缓存数据:@CachePut 用于强制将方法的返回值存储到缓存中,无论缓存中是否已存在相同的键。这对于确保缓存中的数据是最新的非常有用,特别是在需要手动更新缓存数据时。
- 动态生成缓存键:@CachePut 允许你使用 Spring Expression Language (SpEL) 表达式来动态生成缓存项的键。这使得你可以根据方法的参数或其他条件来生成缓存键,以确保不同的缓存项具有不同的键。
- 条件性更新:@CachePut 支持 condition 和 unless 属性,可以根据条件来控制是否执行缓存更新操作。这使你可以在特定条件下才更新缓存,从而更加灵活地管理缓存。
- 清空指定缓存项:通过配置 allEntries 属性为 true,可以清空与指定缓存相关的所有缓存项,而不仅仅是更新一个特定的缓存项。
- 控制更新时机:使用 beforeInvocation 属性,你可以控制是在方法执行之前还是方法执行成功后触发缓存更新。
注:
- @CachePut 注解用于更新缓存中的数据,不同于 @Cacheable,它会执行方法体,并将方法返回的值存入缓存中,以确保缓存中的数据是最新的。
- 如果缓存中的数据不存在,@CachePut将创建一个新的缓存项。
基本用法示例:
@CachePut(value = "xx",key = "'cid:'+#cid")
用法内属性解释:
@CachePut
注解用于将方法的返回值存储到缓存中,通常用于更新缓存中的数据。- 与
@Cacheable
不同,它不会检查缓存中是否已存在相同的键,而是直接将方法的返回值存入缓存,以确保缓存中的数据是最新的。- 这对于更新缓存项非常有用,以确保缓存中的数据与后端数据保持同步。
@CacheEvict
是 Spring Framework 中的一个注解,用于从缓存中移除指定的缓存项或清空整个缓存。
@CacheEvict方法作用:
- 清空指定缓存项:你可以使用 @CacheEvict 来清空一个或多个特定缓存中的缓存项,以确保缓存中的数据保持最新或满足特定条件时清除缓存。
- 条件性清除:@CacheEvict 支持 condition 和 unless 属性,可以根据条件来控制是否执行缓存清除操作。这允许你在满足特定条件时才清除缓存,从而更加灵活地管理缓存。
- 清空整个缓存:通过设置 allEntries 属性为 true,你可以清空整个缓存,而不仅仅是清除特定的缓存项。这对于需要在某些情况下全局清空缓存的场景非常有用。
- 控制清除时机:使用 beforeInvocation 属性,你可以控制是在方法执行之前还是方法执行成功后触发缓存清除操作。
- 清除缓存的多个条目:可以通过 key 属性设置一个缓存键表达式,以删除匹配特定键模式的缓存项。这允许你按一定的模式来删除缓存项。
@CacheEvict 注解的主要作用是从缓存中移除指定的缓存项或清空整个缓存,以确保缓存中的数据保持最新或根据条件来清除缓存。它提供了多个属性,使你可以根据需要来配置清除缓存的方式和时机,以满足特定的业务需求。
基本用法示例:
@CacheEvict(value = "xx",key = "'cid:'+#cid",allEntries = true)
用法内属性解释:
- value 属性:设置为 "xx",表示要清除名为 "xx" 的缓存。通常,你需要在配置中定义相应的缓存管理器,以确保它与这个缓存名称关联。
- key 属性:使用 SpEL 表达式 "'cid:'+#cid" 来生成缓存项的键。这个键将由方法的 cid 参数值动态生成,前缀为 "cid:"。这将导致匹配 "cid:" 后跟 cid 参数值的缓存项被清除。
- allEntries 属性:设置为 true,表示清除整个缓存。如果 allEntries 设置为 true,则会忽略 key 属性,而是清除指定缓存中的所有缓存项。在这个示例中,不管 cid 参数的值如何,都会清空名为 "xx" 的缓存中的所有内容。
@Cacheable
、@CachePut
和@CacheEvict
是 Spring Framework 中用于管理缓存的注解,它们有不同的作用和行为:
- @Cacheable:
- 作用:@Cacheable 用于声明一个方法的返回值可以被缓存,即当方法被调用时,Spring会首先检查缓存,如果缓存中存在相应的结果,就会返回缓存的值而不执行方法体。
- 主要用途:提高性能,避免重复执行相同的方法,适用于读取操作,不用于更新数据。
- 配置:可以指定缓存的名称、缓存键、条件等。
- @CachePut:
- 作用:@CachePut 用于强制将方法的返回值存储到缓存中,通常用于更新缓存中的数据。
- 主要用途:更新缓存,将方法返回的值放入缓存,适用于写入操作。
- 配置:可以指定缓存的名称、缓存键、条件等。
- @CacheEvict:
- 作用:@CacheEvict 用于从缓存中移除指定的缓存项或清空整个缓存。
- 主要用途:清除缓存项,使缓存中的数据保持最新或根据条件来清除缓存。
- 配置:可以指定缓存的名称、缓存键、条件、是否清空整个缓存等。
区别总结:
@Cacheable
用于缓存方法的返回值,避免重复执行方法,适用于读取操作。@CachePut
用于将方法的返回值存储到缓存中,通常用于更新缓存中的数据,适用于写入操作。@CacheEvict
用于清除缓存项,可以清空指定缓存项或整个缓存。关于使用:
这些注解可以根据具体的业务需求来组合使用,以实现灵活的缓存策略。例如,可以使用
@Cacheable
缓存读取操作的结果,使用@CachePut
更新缓存项,使用@CacheEvict
清除缓存中的数据,以满足不同的缓存需求。
当涉及到 Redis 时,"击穿"、"穿透"和"雪崩"是一些常见的问题,涉及缓存系统的高可用性和稳定性。下面我将对这三个问题进行详细解释:
- 击穿(Cache Breakdown):
出现在热点数据失效的情况下。当一个特定的键失效并且接收到了大量的并发请求,这些请求会绕过缓存直接访问数据库,导致数据库压力骤增。这是因为缓存失效后,下一次访问时无法从缓存中获取数据,而必须去数据库中获取。
- 穿透(Cache Penetration):
当恶意用户请求一个不存在于缓存和数据库中的键时,缓存系统无法提供数据,这些请求会直接访问数据库。这可能会导致数据库负载增加,甚至引发拒绝服务攻击。为了应对穿透问题,可以在查询不存在键时设置一个空值或者采用布隆过滤器等方法来过滤无效请求。
- 雪崩(Cache Avalanche):
当缓存中大量的键同时失效,导致大量请求直接访问后端数据库,使得数据库压力骤增,甚至崩溃。这通常是由于缓存中的数据设置了相同的过期时间,导致在同一时间大量的键失效,引发雪崩效应。为了避免雪崩问题,可以采用随机的过期时间、添加热点数据的预加载等策略。
为了应对这些问题,可以采取以下一些解决方案:
- 对于击穿问题,可以使用互斥锁或者设置短暂的过期时间来保护热点数据,确保缓存中有有效的数据。
- 对于穿透问题,可以使用布隆过滤器等技术来过滤无效请求,确保缓存系统只处理有效的请求。
- 对于雪崩问题,可以采用分布式缓存、多级缓存、缓存预热等策略,保证缓存中的数据分布均匀,避免大量数据同时失效。