Redis简介
Redis(Remote Dictionary Server )远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存也可持久化的日志型、Key-Value(NoSQL)数据库。
为什么使用Redis:
-
性能极高,基于内存,读的速度是110000次/s,写的速度是81000次/s
-
丰富的数据类型,支持string、hash、list、set及zset多种数据类型
-
原子性,所有操作都是原子性的,支持事务
-
丰富的特性,支持发布订阅、通知、过期策略等
-
支持持久化,可以将内存中的数据保存在磁盘中,重启后再次加载
-
支持分布式,理论上可以无限扩展
-
单线程,没有线程并发问题,Redis5.0后支持多线程
Redis的数据类型
它主要提供了5种数据类型:字符串(string)、哈希(hash)、列表(list)、集合(set)、有序集合(zset)。Redis还提供了Bitmap、HyperLogLog、Geo类型,但这些类型都是基于上述核心数据类型实现的。5.0版本中,Redis新增加了Streams数据类型,它是一个功能强大的、支持多播的、可持久化的消息队列。
1. string可以存储字符串、数字和二进制数据,除了值可以是String以外,所有的键也可以是string,string最大可以存储大小为512M的数据。
2. list保证数据线性有序且元素可重复,它支持lpush、blpush、rpop、brpop等操作,可以当作简单的消息队列使用,一个list最多可以存储2^32-1个元素。
3. hash的值本身也是一个键值对结构,最多能存储2^32-1个元素。
4. set是无序不可重复的,它支持多个set求交集、并集、差集,适合实现共同关注之类的需求,一个set最多可以存储2^32-1个元素。
5. zset是有序不可重复的,它通过给每个元素设置一个分数来作为排序的依据,一个zset最多可以存储2^32-1个元素。
事务
Redis提供的事务是将多个命令打包,然后一次性、按照先进先出的顺序(FIFO)有序的执行。在执行过程中不会被打断(在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中),当事务队列中的所以命令都被执行(无论成功还是失败)完毕之后,事务才会结束。
-
multi 启动事务
-
exec 提交事务
-
discard 放弃事务
-
watch 监视一个或多个键,如果有其他客户端修改键的值,事务将失败
Springboot集成Redis
redis读取数据的流程:
-
先查询缓存
-
如果查到直接返回
-
如果查不到,查询数据库
-
数据库查到,保存缓存中
-
数据库查不到返回null
集成步骤:
1、导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2、配置文件
# 主机
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
3、配置类
编程式
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
//创建redis的操作对象
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;
}
}
声明式
/**
* Redis配置
*/
@Configuration
@EnableCaching
public class RedisConfig {
/**
* 声明式缓存的配置
* @return
*/
@Bean
public RedisCacheConfiguration provideRedisCacheConfiguration(){
//加载默认配置
RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig();
//返回Jackson序列化器
return conf.serializeValuesWith(
RedisSerializationContext.SerializationPair
.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
}
4、主要实现
编程式:
public Food getFoodById(Long id) {
//获得字符串操作对象
ValueOperations<String, Object> ops = redisTemplate.opsForValue();
//先查询redis
Food food = (Food) ops.get(PREFIX + id);
//如果redis缓存存在,就返回数据
if (food != null){
System.out.println("Redis查到,返回" + food);
return food;
}
//如果redis没有查到,就查数据库
food = foodMapper.selectById(id);
//数据库查到数据,就保存到redis
if (food != null){
System.out.println("mysql查到,返回" + food);
ops.set(PREFIX + id,food);
return food;
}
//mysql没有查到数据,就返回null
return null;
}
声明式:
@Cacheable(cacheNames = "Food",key = "T(String).valueOf(#id)")
@Override
public Food getFoodById(Long id) {
return foodMapper.selectById(id);
}
/**
* 删除数据同时删除分页缓存
* @param id
*/
@Caching(evict = {@CacheEvict(cacheNames = "Food",key = "T(String).valueOf(#id)"),
@CacheEvict(cacheNames = "food-page",allEntries = true)})
@Override
public void removeFoodById(Long id) {
foodMapper.deleteById(id);
}
/**
* 更新数据,同时删除分页缓存
* @param food
* @return
*/
@Caching(put = @CachePut(cacheNames = "Food",key = "T(String).valueOf(#food.id)"),
evict = @CacheEvict(cacheNames = "food-page",allEntries = true))
@Override
public Food updateFoodById(Food food) {
foodMapper.updateById(food);
return food;
}
/**
* 添加数据,同时删除分页缓存
* @param food
* @return
*/
@Caching(put = @CachePut(cacheNames = "Food",key = "T(String).valueOf(#food.id)"),
evict = @CacheEvict(cacheNames = "food-page",allEntries = true))
@Override
public Food addFood(Food food) {
foodMapper.insert(food);
return food;
}