优点:java查询时,首先从redis中查,查不到再从mysql中查
reids是内存中查,是查询键和键值(hash),mysql是从磁盘中查,还需要解析复杂的sql语句。
零、下载安装
一、Redis启动连接和关闭
(一)三种启动方式
1、直接启动
redis-server
2、指定配置文件启动(推荐)
在redis-server命令加上配置文件的路径,这样方便进行一些设置
在redis.conf所在目录下运行命令:
redis-server redis.conf
3、设置为开机启动
不同的系统有不同的设置方式
(二)关闭服务
redis-cli shutdown
(三)redis客户端连接
redis客户端工具有两个:
- redis-cli:命令行的客户端工具
- redis-desktop:有界面版
redis-cli启动方式如下:
redis-cli
查看是否连接成功,键入ping,redis会回复pang
二、Redis常用命令
(一)配置文件修改方式
linux下文档太长的话,文档内搜索文本:
/文本
设置后台启动
前台启动:占用一个窗口,命令行敲不了其他命令
后台启动:启动完之后还可以敲其他命令,就像后台程序一样
daemonize yes
设置日志存储目录,方便有问题后续排查
logfile /opt/software/redis-6.2.2/log
绑定指定ip,指定谁可以访问这个redis,可以设置多个ip,空格分隔
bind ip ip
(二)Redis基础命令
1、启动redis-cli客户端。
redis-cli
2、常用命令
- 活动符合规则的键 keys
- 判断键是否存在 exists
- 删除键 del
- 获得简直的类型 type
- 帮助命令 help
- 退出客户端 quit/exit
3、查看和删除键:
keys删除所有键
查看所有键:keys *
三、Redis的数据类型
(一)string类型
介绍string类型是字符串类型,是Redis中最基本的数据类型,他能存储任意形式的内容,一个string类型值得最大容量为1GB。
Redis数据类型之string
命令 | 格式 | 解释 |
---|---|---|
set | set key value | 给key设置一个Value(字符串类型的) |
get | get key | 获取key的值 |
incr | incr key | 对key的值递加+1(值必须是数字) |
decr | decr key | 给key的值递减-1(值必须是数字) |
strlen | strlen key | 获取key值的长度 |
(二)hash类型
介绍:hash类型的值存储了字段和字段值的映射,字段和字段值只能是字符串 ,不知道出其他数据类型,hash类型的值里面最多存储2的32次方-1个字段,hash类型比较适合存储对象。
Redis数据类型之hash
命令 | 格式 | 解释 |
---|---|---|
hset | hset key field value | 向hash中添加字段和值 |
hget | hget key field | 获取hash中指定字段的值 |
hgetall | hgetall key | 获取hash中所有的字段和值 |
hexists | hexists key field | 判断hash中是否包含指定字段 |
hincrby | hincrby key field num | 对hash中指定字段的值递增 |
hdel | hdel key field | 删除hash中指定的字段 |
hkeys/hvals | hkeys/hvals key | 获取hash中所有字段或字段值 |
(三)list类型
介绍:list是一个有序的字符串列表,列表内部使用的是双向链表(linked list)实现的,list类型的值最多存储2的32次方-1个元素。list类型比较适合作为丢列使用,使用lpush+rpop来实现
命令 | 格式 | 解释 |
---|---|---|
lpush | lpush key value | 从列表左侧添加元素 |
rpush | rpush key value | 从列表右侧添加元素 |
lpop | lpop key | 从列表左侧弹出元素 |
rpop | rpop key | 从列表右侧弹出元素 |
llen | llen key | 获取列表的长度 |
lrange | lrange key start stop | 获取列表指定区间的元素 |
lindex | lindex key index | 获取列表指定角标的元素 |
(四)set类型
介绍:set集合中的元素都是不重复的,无需的,set类型的值最多存储2的32次方-1个元素,set比较设在去重场景下使用。
命令 | 格式 | 解释 |
---|---|---|
sadd | sadd key value | 从集合中添加元素 |
smembers | smembers key | 获取集合中所有元素 |
srem | srem key value | 从集合中删除指定元素 |
sismember | sismember key value | 判断集合中是否包含指定元素 |
sdiff | sdiff key1 key2 | 获取两个集合的差集 |
sinter | sinter key1 key2 | 获取两个集合的交集 |
sunion | sunion key1 key2 | 获取两个集合的并集 |
其中,key也可以作为集合的索引。
(五)sortedSet类型
介绍:有序集合,在集合类型的基础上为集合中的每个元素都关联了一个分数,通过分数为集合中的成员进行从小到大的排序。
比较适合用于TopN的场景
命令 | 格式 | 解释 |
---|---|---|
zadd | zadd key value | 向集合中添加元素 |
zscore | zscore key value | 获取集合中所有元素的分值 |
zrange | zrange key value | 获取集合指定元素的排名(正序) |
zrevrange | zrevrange key value | 获取集合指定元素的排名(倒序) |
zincrby | zincrby key value | 给集合中指定元素增加分值 |
zcard | zcard key | 获取集合中元素的数量 |
下图中的1、2、3作为分数来进行排序
(六)更多数据类型
例如用于计数的HyperLogLog,用于支持存储地理位置信息的Geo。
四、Redis的java客户端
(一)Jedis
redis的java客户端其实有很多,Jedis是官方推出的一款java客户端
(二)Redis Template的使用
spring-data-redis用spring提供,对底层开发包(Jedis,jRedis进行了高度封装,Redis Template来自于这个包,RedisTemplate提供redis各种操作、异常处理及序列化秒支持发布订阅,并对spring-cache进行了实现。
SpringBoot下的依赖导入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.4.7</version>
</dependency>
配置类设置端口
spring:
redis:
host: 192.168.253.151
对应java对象(例如本例中的category,resultVO)添加implements Serializable。
@Autowired
private RedisTemplate redisTemplate;
@GetMapping("/listTopCategoryStruct")
public ResultVO listTopCategoryStruct(){
if (redisTemplate.hasKey("category")){
//先查看redis里有没有数据
ResultVO resultVO = (ResultVO) redisTemplate.opsForValue().get("category");
return resultVO;
}
//有就直接用
//没有就调用service从mysql里查,将查询结果放入到redis
ResultVO resultVO=categoryService.listTopStruct();
redisTemplate.opsForValue().set("category",resultVO);
return resultVO;
}
(三)Java序列化的问题
不建议使用Java自带的序列化,因为java自带的序列化码流大效率低并且不能跨语言
(每一台服务器不一定全都用java写)
(四)缓存框架
重写listTopCategoryStruct方法如下:
@GetMapping("/listTopCategoryStruct")
@Cacheable("categoryVO")
public ResultVO listTopCategoryStruct() {
return categoryService.listTopStruct();
}
对应java对象(例如本例中的category,resultVO)删除implements Serializable。
写一个如下的配置类
package com.neutech.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.neutech.entity.Category;
import com.neutech.vo.ResultVO;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
// 创建redisTemplate对象
RedisTemplate redisTemplate = new RedisTemplate();
// 设置连接池
redisTemplate.setConnectionFactory(factory);
// 字符串解析器
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// jackson提供的对象转json解析器
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(ResultVO.class);
ObjectMapper objectMapper = new ObjectMapper();
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置key和value的转换器
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
return redisTemplate;
}
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
//string序列化方式 对key序列化
RedisSerializer<String> strSerializer = new StringRedisSerializer();
//json 序列化方式对value序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =new Jackson2JsonRedisSerializer(ResultVO.class);
//解决查询缓存转换异常
ObjectMapper objectMapper = new ObjectMapper();
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
//定制缓存数据序列化方式时效
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig()
//过期时间设置为 Duration#ZERO永远不过期
.entryTtl(Duration.ofDays(1))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(configuration).build();
return redisCacheManager;
}
}
注意:
(一)
listTemplate底层默认转化规则,默认使用java自带的序列化。
(二)
错误:
java.lang.IllegalArgumentException: DefaultSerializer requires a Serializable payload but received an object of type
:序列化问题,给向Redis输入数据的类和实体类都加上implements Serializable即可。
(三)
redis默认自带16的库(0-15),默认用0号库
(四)
在增删改这种对数据有操作的地方一定要注意更新缓存。
@CacheEvict(cacheNames = {"categoryVO"})
(五)
什么样的数据适合做缓存?不要乱用缓存。
不频繁修改的数据适合做缓存,考虑数据量(不要超过缓存量(注意linux系统的缓存大小))
五、redis持久化原理
redis的持久化,简单来说就是把内存中的数据持久化到磁盘中,保证重启之后能恢复之前的数据,redis支持两种持久化方式ROB(默认)、AOF,两种方式可单独使用可组合使用。
1.ROB
ROB持久化是通过快照完成的,当符合一定条件时,redis会自动执行快照操作将数据存到磁盘中,默认存储在dump.rdb文件中
执行时机:
在3600秒之内如果操作一次就3600每秒拍一次照
在300秒内,如果操作一百次就300每秒拍一次照
在60秒内,如果操作10000此就60每秒拍一次照
ROB的优点是由于存储的有数据快照文件,恢复数据方便,缺点是会丢失最后一次快照更改后的所有数据,注意是redis异常停止的时候
2.AOF
aof是通过日志文件的方式,默认情况下没有开启,可以通过appendonly参数开启
aof日志文件的保存位置和ROB相同,同时dir参数设置的
cli内写命令,用于切换持久化方式
config set appendonly yes
先执行临时配置,等一小会儿修改配置文件重启redis
AOF的写时机?
(每隔一秒钟写一次)
appendfsync参数来设置