什么是Redis
Redis(Remote Dictionary Server )远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存也可持久化的日志型、Key-Value(NoSQL)数据库。
Redis的特点
1.性能极高,读写速度快,基于内存
2.支持多种数据类型,列如string,hash,list,set,zset
3.原子性的,支持事务
4.丰富的特性,支持发布订阅和通知
5.支持持久化,将内存的数据保存在磁盘,重启后再次加载
6.支持分布式,理论上可以无限扩展
7.单线程,没有并发问题,但在5.0版本后支持多线程
应用场景
1. 缓存
2. 分布式锁
3. 分布式Session
4. 消息队列等
Redis数据类型
string(字符串类型)
键值对格式,常用命令有set,get
应用场景:
-
缓存
-
分布式ID
-
分布式锁
-
全局Session
-
全局计数器
Hash(一个键,多个值)
应用场景:保存对象的多个属性
和string的对比,优势是:可以灵活读写对象的部分属性
常用命令:hmget(读取对象属性),hgetall(读取对象所有属性),hdel(删除对象属性)
List(链表结构)
有序可重复
应用场景:
-
模拟数组、栈、队列等数据结构
-
线型结构,如:粉丝、点赞列表
-
消息队列
常用命令:lpush左入,lpop左出,rpush右入,rpop右出
Set
set是无序的、不可重复的集合。
应用场景:
-
点赞数(避免重复)
-
社交关系(共同关注、可能认识)
常用命令sadd添加,sismember判断是否有这个元素,sinter取交集,sdiff取差集,sunion取并集
zset
zset是有序的、不可重复的集合。
应用场景:
-
排行榜
常用命令:zadd添加, zrangebyscore读取数据
Redis在开发中的使用
编程式缓存
首先想要用Redis必须导入相关依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
再添加配置文件
# 服务器地址
spring.redis.host=localhost
# 端口
spring.redis.port=6379
# 数据库名
spring.redis.database=0
# 最大连接数
spring.redis.jedis.pool.max-active=100
# 最大闲置时间
spring.redis.jedis.pool.max-wait=100ms
# 最大闲置连接数
spring.redis.jedis.pool.max-idle=100
# 最小闲置连接数
spring.redis.jedis.pool.min-idle=10
接下来就需要在config包下创建RedisTemplate配置类
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
// 配置序列化器
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化器
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
然后还需要引入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
用来解决缺少的依赖
在使用方法上加入注解
@Cacheable(cacheNames = "Student",key = "T(String).valueOf(#id)")
声明式缓存
推荐使用声明式,编程式缓存使用复杂,代码侵入性高,推荐使用声明式缓存,通过注解来实现热点数据缓存。
声明式在编程式的基础上,需要在配置类中额外加入以下代码
@Configuration
public class RedisConfig {
@Bean
public RedisCacheConfiguration provideRedisCacheConfiguration(){
//加载默认配置
RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig();
//返回Jackson序列化器
return conf.serializeValuesWith(
RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
然后还需要添加一个
//启动缓存
@EnableCaching注解
最终如下
@Configuration
//启动缓存
@EnableCaching
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
// 配置序列化器
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson序列化器
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
@Bean
public RedisCacheConfiguration provideRedisCacheConfiguration(){
//加载默认配置
RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig();
//返回Jackson序列化器
return conf.serializeValuesWith(
RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
}
注意事项,如果我们进行增删改查导致mysql数据与redis数据不一样,mysql数据如果删除了,redis将读到mysql里没有数据,所有我们在做操作的时候,需要使用组合注@Cacing
列如一下代码
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
@Autowired
private StudentMapper studentMapper;
public static final String PREFIX = "Student-";
@Autowired
private RedisTemplate<String,Object>redisTemplate;
@Cacheable(cacheNames = "Student-Page",key = "T(String).valueOf(#current)")
@Override
public Page<Student> getStudentPage(Long current, Long size) {
return studentMapper.selectStudentPage(new Page<>(current,size));
}
@Cacheable(cacheNames = "Student",key = "T(String).valueOf(#id)")
@Override
public Student getStudentById(Long id){
return studentMapper.selectById(id);
}
// @CacheEvict(cacheNames = "Student",key = "T(String).valueOf(#id)")
//使用组合注解,删除一个学生时,将所有分页缓存删掉
@Caching(
evict = {@CacheEvict(cacheNames = "Student", key = "T(String).valueOf(#id)"),
@CacheEvict(cacheNames = "Student-Page", allEntries = true)
}
)
@Override
public void removeStudentById(Long id) {
studentMapper.deleteById(id);
}
// @CachePut(cacheNames = "Student",key = "T(String).valueOf(#student.stuId)")
@Caching(
put = @CachePut(cacheNames = "Student",key = "T(String).valueOf(#student.stuId)"),
evict = @CacheEvict(cacheNames = "Student-Page", allEntries = true)
)
@Override
public Student updateStudentById(Student student) {
studentMapper.updateById(student);
return student;
}
// @CachePut(cacheNames = "Student",key = "T(String).valueOf(#student.stuId)")
@Caching(
put = @CachePut(cacheNames = "Student",key = "T(String).valueOf(#student.stuId)"),
evict = @CacheEvict(cacheNames = "Student-Page", allEntries = true)
)
@Override
public Student addStudent(Student student) {
studentMapper.insert(student);
return student;
}
该代码就是在进行添加,修改,删除的时候,对redis缓存同步进行了删除操作,所有就不出现读到脏数据的情况。
总结
Redis作为一个高性能的键值存储数据库,具有出色的性能和灵活的数据结构。它在诸多场景中展现出独特的优势,如缓存层、会话存储、实时应用程序和统计数据等。通过充分了解Redis的特性和应用,我们可以更好地利用它来构建高效、可扩展的应用程序。希望通过本文的介绍,读者能对Redis有更深入的理解,并能正确使用它来满足不同的需求。