- Redis中的数据是以键值对形式存储的,且二进制安全
- Redis中默认不支持中文,都是以二进制存储的
- 要正常显示中文,在登陆客户端时,使用redis-cli --raw命令登录
一、redis的数据结构
- redis存储的是:key-value格式的数据,其中key都是字符串,value有5种不同的数据结构
-
- 字符串类型 string
- 哈希类型 hash:map格式
- 列表类型 list:linkedlist格式;支持重复元素
- 集合类型 set:不允许重复元素
- 有序集合类型 sortedset:不允许重复元素,且元素有顺序
1. 通用命令
- 获取键对应的value的类型:type key
- 判断:exists key
- 查看所有键:keys *
- 查找以xx为结尾的键:keys *xx
- 删除所有键:flushall
- 查看一个键的过期时间(time to live):ttl key(最后显示-2表示过期)
- 设置一个键的过期时间:expire key 时间(秒)
- 设置一个键值对的过期时间:setex key 时间(秒) value
2. 字符串类型 string
- 添加:set key value
- 查看:get key
- 删除:del key
3. 列表类型 list
元素可以重复
可以添加一个元素到列表的头部(左边)或者尾部(右边)
- 添加:
-
- lpush key value:将元素加入列表左表
- rpush key value:将元素加入列表右表
- 查看:
-
- lrange key start end:范围获取
- 删除:
-
- lpop key:删除列表最左边的元素,并将元素返回
-
-
- lpop key 2:删除最左边两个元素
-
-
- rpop key:删除列表最右边的元素,并将元素返回
- ltrim key start end:删除列表中指定范围以外的元素
- 查看列表元素个数
-
- llen key
- 简单的消息队列
-
- lpush命令从列表头部添加一个元素
- rpop命令从列表尾部删除一个元素
4. 集合类型 set
元素不可以重复,
元素不具有顺序
- 添加:
-
- sadd key value
- 查看:
-
- smembers key:获取set元素集合中所有元素
- 删除:
-
- srem key value:删除set集合中的某个元素
- 判断一个元素是否在集合中
-
- sismember key value
- 运算
-
- sinter key [key ...]:返回一个集合的全部成员,该集合是所有给定集合的交集。
- sunion key [key ...]:返回一个集合的全部成员,该集合是所有给定集合的并集。
- sdiff key [key ...]: 返回所有给定 key 与第一个 key 的差集
5. 有序集合类型 sortedset
元素不可以重复(但分数可以重复)
元素有顺序
- 添加:
-
- zadd key score value
- 查看:
-
- zrange key start end (withscores):(同时输出分数)
- zscore key value:查看某个元素的分数
- zrank key value:查看某个元素的排名(从小到大)
- zrevrank key value:查看某个元素的排名(从大到小,rev->reverse反转)
- 删除:
-
- zrem key value
6. 哈希类型 hash
字符类型的字段和值的映射表(一个键值对的集合)
适合用来存储对象
- 添加:hset key field value
- 查看:
-
- hget key field:获取指定的field对应的值
- hgetall key:获取所有的field和value
- 删除:hdel key field
- 判断摸个键值对是否存在:hexists key field
- 获取哈希中的所有键:hkeys key
- 获取哈希中的所有键的数量:hlen key
二、发布订阅模式
- 将消息发送到指定的频道:publish channel(频道名称) message(发布的消息)
- 订阅频道:subscribe channel [channel ...]
- 局限性:
-
- 消息无法持久化
- 无法记录历史消息
三、消息队列Stream
Stream是Redis5.0引入的一个新的数据结构,是一个轻量级的消息队列
可以解决发布订阅功能的一些局限性(消息无法持久化、无法记录历史消息)
1. 集合
- 添加
-
- xadd key * field value
-
-
- *表示自动生成一个消息id,可自己制定,格式:如1-0、2-0
- 第一个整数表示一个时间戳,第二个整数表示一个序列号
- *自动会保证id是递增的,手动需要保证id递增
-
- 查看
-
- xlen key:查看Stream中消息的数量
- xrange key - +:查看所有的消息
- xread COUNT 2 BLOCK 1000 STREAMS key 0
-
-
- 一次读取2条消息
- block表示没有消息就阻塞1000毫秒(1秒)
- streams后面指定消息队列,0表示从头开始读取,1表示从第二条消息开始读取,如果超出消息数量,就会阻塞1秒,返回nil。要获取从现在开始,以后最新的消息,则streams后指定$
-
- 删除
-
- xdel key id:删除id的消息
- xreim key MAXLENS 0:删除所有的消息
2. 消费者组
- 创建
-
- xgroup create key 组名称 id
- 添加
-
- xgroup createconsumer 组名称 消费者名
- 查看
-
- xinfo groups key:查看组信息
- xreadgroup group 组名称 消费者名称 COUNT 2 BLOCK 3000 key >
-
-
- 一次读取两条消息
- 消息名 >:从这个消息中读取最新消息
-
四、持久化
- redis是一个内存数据库,当redis服务器重启,获取电脑重启,数据会丢失,我们可以将redis内存中的数据持久化保存到硬盘的文件中
redis持久化机制:
1.1. RDB
默认方式,不需要进行配置,默认就是用这种机制
- 在一定的间隔时间中,检测key变化情况,然后持久化数据
-
- 编辑redis.windows.conf文件
# after 900 sec (15 min) if at least 1 key changed
save 900 1
# after 300 sec (5 min) if at least 10 keys changed
save 300 10
# after 60 sec if at least 10000 keys changed
save 60 10000
- 编辑redis.windows.conf文件
- 重新启动redis服务器,并指定配置文件名称
redis-server.exe redis.windows.conf
1.2. AOF
日志记录的方式,可以记录每一条命令的操作。可以每一次命令操作后,持久化数据
- 编辑redis.windows.conf文件
-
- appendonly no(关闭aof)--> appendonly yes(开启aof)
- appendfsync always:每一次操作都进行持久化
- appendfsync everysec:每隔一秒进行一次持久化
- appendfsync no:不进行持久化
五、Java客户端 Jedis
https://redis.io/clients
- Jedis:以Redis命令作为方法名称,学习成本低,简单实用。但Jedis实例线程不安全,多线程环境下需要连接池来使用。
- Lettuce:基于Netty实现,支持同步、异步和响应式编程方式,且线程安全。支持Redis的哨兵模式、集群模式和管道模式。
- Redisson:基于Redis实现的分布式、可伸缩的Java数据结构集合,包含了诸如Map、Queue、Lock、Semaphore、AtomicLong等强大功能。
1. 使用步骤:
- 下载Jedis的jar包 :https://github.com/redis/jedis
- 使用
-
- 获取链接
Jedis jedis = new Jedis("localhost", 6379);
Jedis jedis = new Jedis();//如果使用空参构造,默认值“localhost”,6379 - 设置密码:jedis.auth("123123");
- 选择库:jedis.select(0);
- 插入数据:String result = jedis.set("name","张三");
- 获取数据:String name = jedis.get("name");
- 释放资源:
- 获取链接
if(jedis != null){
jedis.close();
}
2. Jedis操作各种redis中的数据结构
2.1. 字符串类型string
- set(key, value)
- get(key)
- setex(key, second, value)
可以使用setex()方法存储可以指定过期时间的key value
如jedis.setex("activecode",20,hehe);//将active:hehe键值对存入redis,并且20秒后自动删除该键值对。
2.2. 哈希类型hash
map格式
- hset(key, filed, value)
- hget(key, filed)
- hgetAll(key)
2.3. 列表类型list
linkedlist格式。支持重复元素
- lpush(key, ...strings)/rpush(key, ...strings) //...string是指后面多个数据
- lpop(key)/rpop(key)
- lrange(start, end):范围获取
2.4. 集合类型set
不允许重复元素
- sadd
2.5. 有序集合类型sortedset
不允许重复元素,且元素有顺序
- zadd
3. Jedis连接池
- Jedis线程不安全,频繁创建和销毁连接有性能损耗,因此使用Jedis连接池代替Jedis的直连方式。
- 使用Jedis连接池,Jedis.close()的操作就会归还,而不是销毁。
public class JedisConnectFactory{
private static final JedisPool jedisPool;
static{
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
//最大连接
jedisPoolConfig.setMaxTotal(8);
//最大空闲连接
jedisPoolConfig.setMaxIdle(8);
//最小空闲连接
jedisPoolConfig.setMinIdle(8);
//设置最长等待时间,ms
jedisPoolConfig.setMaxWaitMillis(1000);
jedisPool = new JedisPool(jedisPoolConfig, localhost, 6379, 1000,"123123");
}
//获取Jedis对象
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
六、SpringDataRedis
- SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis
- 官网地址:https://spring.io/project/spring-data-redis
- 提供了对不同Redis客户端的整合(Lettuce和Jedis)
- 提供了RedisTemplate统一API来操作Redis
- 支持Redis的发布订阅模式
- 支持Redis哨兵和Redis集群
- 支持基于Lettuce的响应式编程
- 支持基于JDK、JSON、字符串、Spring对象的数据序列化和反序列化
- 支持基于Redis的JDKCollection实现
API | 返回值类型 | 说明 |
redisTemplate.opsForValue() | ValueOperations | 操作String类型数据 |
redisTemplate.opsForHahs() | HashOperations | 操作Hash类型数据 |
redisTemplate.opsForList() | ListOperations | 操作List类型数据 |
redisTemplate.opsForSet() | SetOperations | 操作Set类型数据 |
redisTemplate.opsForZSet() | ZSetOperations | 操作SortedSet类型数据 |
redisTemplate | 通用的命令 |
1. SpringDataRedis简单应用
1.1. 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
1.2. 配置文件
spring:
redis:
host: 127.0.0.1
port: 6379
password: 123123
lettuce:
pool:
max-active: 8 # 最大连接
max-idle: 8 # 最大空闲连接
min-idle: 0 # 最小空闲连接
max-wait: 100 # 连接等待时间,ms
1.3. 编写测试
@SpringBootTest
public class RedisTest{
@Autowired
private RedisTemplate redisTemplate;
@Test
void testString(){
//插入一条String类型数据
redisTemplate.opsForValue.set("name", "李四");
//读取一条String类型数据
Object name = redisTemplate.opsForValue.get("name");
System.out.println(name);
}
}
2. SpringDataRedis的序列化方式
2.1. 自定义
- RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认采用JDK序列化,得到的结果如:\xAC\xED\x00\x05t\x00\x06\xE6\x9d\x8E\xE5\x98\x98
-
- 缺点:可读性差、内存占用较大
- 自定义RedisTemplate,修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer
-
- 缺点:占用额外内存空间,会记录类的字节码
/*没有引入SpringMVC,需引入Jackson依赖*/
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
@Configuration
public class RedisConfig {
//Redis连接工厂不需要创建,SpringBoot会自动创建,只需要@Bean注入一下就可以了
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException{
//创建Template
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
//设置连接工厂
redisTemplate.setConnectionFactory(redisConnectionFactory);
//设置序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
//Key和hashKey采用String序列化
redisTemplate.setKeySerializer(RedisSerializer.string());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
//value和hashValue采用JSON序列化
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
return redisTemplate;
}
}
2.2. StringRedisTemplate
- RedisTemplate会自动把对象序列化成JSON,和反序列化为对象
- 尽管JSON序列化方式可以满足需求,但在反序列化时知道对象的类型,JSON序列化器会将类的class类型写入JSON中,存入Redis,带来额外的内存开销
- 为了节省内存空间,不会使用JSON序列化处理value,统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化
- Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式,省去了定义RedisTemplate的过程
-
- 省去了自定义过程
- 缺点:每次读写,需要手动的把对象、JSON序列化和反序列化
@Autowired
private StringRedisTemplate stringRedisTemplate;
//JSON工具
private static final ObjectMapper mapper = new ObjectMapper();
@Test
void testStringTemplate() throws JsonProcessingException{
//准备对象
User user = new User("张三", 18);
//手动序列化
String json = mapper.writerValueAsString(user);
//写入数据
stringRedisTemplate.opsForValue().set("user:200", json);
//读取数据
String val = stringRedisTemplate.opsForValue().get("user:200");
//反序列化
User user1 = mapper.readValue(val, User.class);
}