SpringBoot整合Redis实现缓存、队列、⼴播
本次主要给各位分享Redis与SpringBoot的集成使⽤,缓存案例,消息队列案例,⼴播案例
初识Redis
Redis是开源的(BSD许可)内存数据结构存储,常⽤作于<K,V>数据库,缓存和消息代理
Redis⽀持的数据结构如下
字符串(String)
哈希/散列/字典(Hash)
列表(List)
集合(Set)
有序集合(sorted set)
主流的Redis-JavaApi框架
Jedis Redis实现的Java客户端,API较为全⾯
Redisson实现了分布式和可扩展的java数据结构,⽀持的数据结构有:List, Set, Map, Queue, SortedSet, ConcureentMap, Lock, AtomicLong, CountDownLatch。并且是线程安全的,底层使⽤Netty 4实现⽹络通信。和jedis相⽐,功能⽐较简单,不⽀持排序,事务,管道,分区等redis特性,可以认为是jedis的补充,不能替换jedis
Lettuce基于Netty的连接实例(StatefulRedisConnection),可以在多个线程间并发访问,且线程安全,满⾜多线程环境下的并发访问,同时它是可伸缩的设计,⼀个连接实例不够的情况也可以按需增加连接实例
注:官⽅推荐使⽤Jedis
springboot 1.5.x版本的默认的Redis客户端是 Jedis实现的,springboot 2.x版本中默认客户端是⽤ lettuce实现的
Springboot集成Redis-配置
⾸先在pom中新增Redis依赖
<!--Redis客户端-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redis依赖commons-pool 这个依赖⼀定要添加 -->
<dependency>
<groupId>org.apachemons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
在springboot启动类增加注解:@EnableCaching
补充:搞到这⾥,有兄弟肯定⼼想,不是推荐使⽤jedis吗,为什么我们此处是⽤的SpringDataRedis,
因为SpringDataRedis中对JedisApi 进⾏了⾼度封装,更加⽅便我们开发,⽽且SpringDataRedis相对于Jedis来说可以⽅便地更换Redis的Java客户端,⽐Jedis多了⾃动管理连接池的特性,⽅便与其他Spring框架进⾏搭配使⽤
在l中增加Redis的配置
spring:
redis:
database: 0
host: 127.0.0.1
port: 6379
password: #没有可以不填
lettuce: #连接池配置
pool:
max-active: 200
max-wait: -1
max-idle: 10
min-idle: 10
timeout: 1000
cache: redis
增加Redis序列化配置
为什么需要这个:因为redis默认的序列化和反序列化是JdkSerializationRedisSerializer完成的,此处我们重写序列化⽅式,是为了防⽌Key或者Value存储到Redis中乱码,导致缓存读取不到或者值乱码的情况
/**
* @author 孤
* @version v1.0
* @Developers 张耀烽
* @serviceProvider xxx
* @description redis配置
* @date 2019年11⽉15⽇ 00:00:00
*/
@Configuration
public class RedisConfig {
//Key的过期时间
private Duration timeToLive = Duration.ofDays(1);
/**
* redis模板,存储关键字是字符串,值jackson2JsonRedisSerializer是序列化后的值
*
* @param
* @return org.RedisTemplate
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
//使⽤Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使⽤JDK的序列化⽅式)
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//使⽤StringRedisSerializer来序列化和反序列化redis的key值
RedisSerializer redisSerializer = new StringRedisSerializer();
//key
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
//value
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
return RedisCacheConfiguration.
defaultCacheConfig().
entryTtl(this.timeToLive). //Key过期时间此处设置1天
serializeKeysWith(RedisSerializationContext.SerializationPair.
fromSerializer(new StringRedisSerializer())).
serializeValuesWith(RedisSerializationContext.SerializationPair.
fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
}
Springboot集成Redis-缓存的使⽤
配置完之后,我们就可以开始愉快的开发了
⽐如此时我们有⼀个service,只需要在查询的⽅法上增加@Cacheable注解即可:
@Cacheable注解:
value代表当前缓存的分组名称(⽅便我们对缓存做管理,不是缓存的value)
key代表当前缓存的Key值
unless表达式,使⽤场景:如果当前⽅法返回null,则不记录缓存
@Service
public class CsdnDemoImpl implements CsdnDemoService {
@Autowired
private CsdnDemoMapper csdnDemoMapper;
@Cacheable(value = "corp_id", key = "#id", unless = "#result == null")
@Override
public DemoDO getDemoInfo(String id) {
DemoInfo(id);
}
}
到此缓存的基本功能我们就实现了,此时我们测试⼀下,访问这个⽅法,先通过@Cacheable注解⾃动查缓存是否存在,由于是第⼀次访问,缓存是肯定不存在的,然后正常执⾏我们的查询,到Mysql中查询,查询到数据后,注解会帮助我们⾃动把结果写⼊到redis 中,key就是参数id,value就是⽅法返回的结果,此时再次访问时,@Cacheable直接在redis中查到缓存,所以会直接返回,⽽不去跟数据库做交互
可以下载RedisDesktopManager(redis可视化⼯具)进⾏配合测试
此时我们的缓存看起来是没问题了,但是深⼊思考下,还是会发现很多问题:
如果这条数据被更新了,此时缓存是⽆感知的,如果我们继续访问查询接⼝,实际上访问的还是更新之前的值,就会出现脏数据如果这条数据被删除了,也是同样的道理
那么如何解决呢,只需要在update⽅法或者delete的⽅法上增加@CacheEvict注解即可
@CacheEvict注解
value和@Cacheable注解的作⽤是⼀样的,标记是哪个缓存分组下的操作
key代表需要更新的缓存Key
@CacheEvict(value = "corp_id", key = "#Id()")
@Override
public void updateSecretInfo(DemoDO demoDO) {
try {
csdnDemoMapper.updateDemoDO(demoDO);
} catch (Exception e) {
e.printStackTrace();
}
}
当调⽤更新的⽅法时,@CacheEvict会先清空Redis中key是⽅法实体中id的Value,删除的接⼝也是同样的写法⾄此,⼀个较为完善的缓存使⽤就完成了
后续会写个不使⽤注解的demo,使⽤springDataRedis提供的API来实现我们的缓存场景
消息队列-点对点以及订阅发布的模式区别
⼴播其实就是队列中的⼀种模式
正常的消息队列是1对1的消费模式,即⼀条消息只能有⼀个消费者消费
⼴播订阅的队列模式是1对N的消费模式,即⼀条消息可以有多个消费者消费
更详细的可以参考我的另⼀篇⽂章:kafka中队列的概念
Springboot集成Redis-消息队列的使⽤
点对点的消息队列
⾸先我们实现消费者相关的代码,思路如下:
定时任务轮询队列中的数据
如果有则消费,没有则阻塞,直到有新的数据或者阻塞超时
使⽤线程池(按照阿⾥巴巴Java开发规范⾃⼰实现)的⽅式,节省系统资源
代码如下:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论