。本篇主要讲解用Redis实现缓存,如果您看完文章有所收获,可以三连支持博主哦~,嘻嘻。
一、前言
- 各位小伙伴们,博主写的Redis专栏有一段时间了,前面讲解了Redis的例如五种常用数据类型、redis实现持久化、主从复制、哨兵模式等等理论知识。接下来,就要开始着重讲解用redis实现各种业务的代码分析和模拟,一起学习吧!
二、pom文件
下面主要介绍重点的依赖:
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--spring cache-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--spring cache连接池依赖包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.2</version>
</dependency>
复制代码
三、配置文件
# mybatis配置
mybatis.mapper-locations=classpath*:com/agan/redis/mapper/xml/*.xml
# 数据库配置
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/springboot_redis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=1234
# 日志配置
logging.level.com.agan=debug
# swagger2配置
spring.swagger2.enabled=true
# cache配置
spring.redis.database=0
spring.redis.host=12.68.5.13
spring.redis.port=6379
spring.redis.password=123456
# 连接池最大连接次数,使用负数表示没有限制
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间
spring.redis.lettuce.pool.max-wait=-1ms
# 连接池最大空闲连接
spring.redis.lettuce.pool.max-idle=8
# 连接池最小空闲连接
spring.redis.lettuce.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=5000ms
复制代码
四、配置类
@Configuration
@EnableCaching
public class RedisConfig {
@Primary
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
redisCacheConfiguration = redisCacheConfiguration
//设置缓存的默认超时时间:30分钟
.entryTtl(Duration.ofMinutes(30L))
//如果是空值,不缓存
.disableCachingNullValues()
//设置key序列化器
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
//设置value序列化器
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()));
return RedisCacheManager
.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
.cacheDefaults(redisCacheConfiguration)
.build();
}
/**
* key序列化器
*/
private RedisSerializer<String> keySerializer() {
return new StringRedisSerializer();
}
/**
* value序列化器
*/
private RedisSerializer<Object> valueSerializer() {
return new GenericJackson2JsonRedisSerializer();
}
}
复制代码
@EnableCaching:
注解会触发一个后处理器(post processor ),它检查每个Spring bean是否存在公共方法(public method)上的缓存注释。 如果找到这样的注释,则自动创建代理以拦截方法调用并相应地处理缓存行为。@Primary:
同种类型的bean时,有该注解的bean具有最优先性
五、核心代码
@Service
@CacheConfig(cacheNames = { "user" })
public class UserService {
private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class);
@Autowired
private UserMapper userMapper;
@Cacheable(key="#id")
public User findUserById(Integer id){
return this.userMapper.selectByPrimaryKey(id);
}
@CachePut(key = "#obj.id")
public User updateUser(User obj){
this.userMapper.updateByPrimaryKeySelective(obj);
return this.userMapper.selectByPrimaryKey(obj.getId());
}
@CacheEvict(key = "#id")
public void deleteUser(Integer id){
User user=new User();
user.setId(id);
user.setDeleted((byte)1);
this.userMapper.updateByPrimaryKeySelective(user);
}
}
复制代码
- 与用上一篇文章相比,可以发现,核心代码量明显减少了很多,这就是SpringCache的强大之处,接下来剖析剖析核心代码里面的注解。
六、剖析SpringCache注解
-
@CacheConfig:
是类级别的注解,统一类的所有缓存key前缀;@CacheConfig(cacheNames = { "user" })代表了该类的所有缓存key值都是"user::"为前缀。
-
@Cacheable(key="#id"):
方法级别的注解,可以将运行结果缓存,以后查询相同的数据,直接从缓存中取,不需要调用方法;id的值作为key。
以上方法被调用时,先从缓存中读取数据,如果缓存没有找到数据,再执行方法体,最后把返回值添加到缓存中。 调用方法传入id=100,那redis对应的key=user::100 ,value通过采用GenericJackson2JsonRedisSerializer序列化为json
@CachePut(key = "#obj.id"):
方法级别的注解,用于更新缓存。
以上方法被调用时,先执行方法体,然后springcache通过返回值更新缓存,即key = "#obj.id",value=User
@CacheEvict(key = "#id"):
方法级别的注解,用于删除缓存。
以上方法被调用时,先执行方法体,在通过方法参数删除缓存
七、SpringCache的"坑"
-
对于redis的缓存,SpringCache只支持String,其他的Hash 、List、Set、ZSet都不支持,所以对于Hash 、List、set、ZSet只能用RedisTemplate。
-
对于多表查询的数据缓存,SpringCache是不支持的,只支持单表的简单缓存。对于多表的整体缓存,只能用RedisTemplate。