一、Redis介绍
Redis诞生于2009年,全称是Remote Dictionary Server远程词典服务器,是一个基于内存的键值型NoSQL数据库。
特征:
- 键值(Key-Value)型,Value支持多种不同的数据结构,功能丰富。
- NoSQL,数据存储灵活。
- 单线程,每个命令具有原子性。
- 低延迟,速度快(基于内存、IO多路复用、良好的编码)。
- 支持数据持久化。
- 支持主从集群、分片集群。
- 支持多语言客户端。
二、认识NoSQL
NoSQL(Not Only SQL):非关系型数据库,数据存储灵活,有键值、文档等多种模型。读写快、易扩展,适合大数据、高并发场景。
SQL | NoSQL | |
---|---|---|
数据结构 | 结构化 | 非结构化 |
数据关联 | 关联的 | 无关联的 |
查询方式 | SQL查询 | 非SQL |
事务特性 | ACID | BASE |
存储方式 | 磁盘 | 内存 |
扩展性 | 垂直 | 水平 |
使用场景 |
|
|
例子 |
|
|
- 存储方式
- 关系型数据库基于磁盘进行存储,会有大量的磁盘IO,对性能有一定影响
- 非关系型数据库,他们的操作更多的是依赖于内存来操作,内存的读写速度会非常快,性能自然会好一些
- 扩展性
- 关系型数据库集群模式一般是主从,主从数据一致,起到数据备份的作用,称为垂直扩展。
- 非关系型数据库可以将数据拆分,存储在不同机器上,可以保存海量数据,解决内存大小有限的问题。称为水平扩展。
- 关系型数据库因为表之间存在关联关系,如果做水平扩展会给数据查询带来很多麻烦
三、Redis常见数据类型及命令
Redis 常见数据类型有 String、Hash、List、Set、Sorted Set 。String 就是字符串,比如存用户信息;Hash 适合存对象,比如用户资料;List 可当队列,实现消息排队;Set 能去重,比如统计在线用户;Sorted Set 带排序,像排行榜场景。
1、String类型
String类型的常见命令:
• SET:添加或者修改已经存在的一个String类型的键值对
• GET:根据key获取String类型的value
• MSET:批量添加多个String类型的键值对
• MGET:根据多个key获取多个String类型的value
• INCR:让一个整型的key自增1
• INCRBY:让一个整型的key自增并指定步长,例如:incrby num 2 让num值自增2
• INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
• SETNX:添加一个String类型的键值对,前提是这个key不存在,否则不执行
• SETEX:添加一个String类型的键值对,并且指定有效期
2、Hash类型
Hash类型,也叫散列,其value是一个无序字典,类似于Java中的HashMap结构。
String结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便:
KEY | VALUE |
---|---|
heima:user:1 | {name:"Jack", age:21} |
heima:user:2 | {name:"Rose", age:18} |
Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD:
KEY | VALUE | |
field | value | |
heima:user:1 | name | Jack |
age | 21 | |
heima:user:2 | name | Rose |
age | 18 |
Hash类型的常见命令:
• HSET key field value:添加或者修改hash类型key的field的值
• HGET key field:获取一个hash类型key的field的值
• HMSET:批量添加多个hash类型key的field的值
• HMGET:批量获取多个hash类型key的field的值
• HGETALL:获取一个hash类型的key中的所有的field和value
• HKEYS:获取一个hash类型的key中的所有的field
• HVALS:获取一个hash类型的key中的所有的value
• HINCRBY:让一个hash类型key的字段值自增并指定步长
• HSETNX:添加一个hash类型的key的field值,前提是这个field不存在,否则不执行
3、List类型
Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。特征也与LinkedList类似:
• 有序
• 元素可以重复
• 插入和删除快
• 查询速度一般
List类型常见命令有:
• LPUSH key element ...:向列表左侧插入一个或多个元素
• RPUSH key element ...:向列表右侧插入一个或多个元素
• LPOP key:移除并返回列表左侧的第一个元素
• RPOP key:移除并返回列表右侧的第一个元素
• LRANGE key start end:返回列表中指定范围内的元素,start、end 从 0 开始,-1 表示最后一个元素
• BLPOP和BRPOP:与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil
4、Set类型
Redis的Set结构与Java中的HashSet类似,可以看做是一个value为null的HashMap。因为也是一个hash表,因此具备与HashSet类似的特征:
• 无序
• 元素不可重复
• 查找快
• 支持交集、并集、差集等功能
Set类型常见命令:
• SADD key member ... :向Set中添加一个或多个元素
• SREM key member ... :移除Set中的指定元素
• SCARD key :返回Set中元素的个数
• SISMEMBER key member:判断一个元素是否存在于Set中
• SMEMBERS:获取Set中的所有元素
• SINTER key1 key2 ... :求多个Set的交集
• SUNION key1 key2 ... :求多个Set的并集
• SDIFF key1 key2 ... :求两个Set的差集
5、Sorted Set类型
Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加 hash表。
SortedSet具备下列特性:
• 可排序
• 元素不重复
• 查询速度快
因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。
SortedSet类型常见命令:
• ZADD key score member:添加一个或多个元素到SortedSet,如果已经存在则更新其score值
• ZREM key member:删除SortedSet中的一个指定元素
• ZSCORE key member:获取SortedSet中的指定元素的score值
• ZINCRBY key increment member:让SortedSet中的指定元素的score值按increment值自增
• ZCARD key:获取SortedSet中的元素个数
• ZRANK key member:获取指定元素在SortedSet中的排名(默认从小到大排序)
• ZCOUNT key min max:统计score值在给定范围内的所有元素的个数
• ZRANGE key min max:按照score排序后,获取指定排名范围内的元素
• ZRANGEBYSCORE key min max:按照score排序后,获取指定score范围内的元素
• ZDIFF、ZINTER、ZUNION:求差集、交集、并集
注意:所有的排名默认都是升序,如果要降序则在命令的Z后面添加REV即可。
四、Redis的java客户端及SpringDataRedis快速入门
1、Redis的几种客户端
• Jedis:以 Redis 命令作为方法名称,学习成本低,简单实用。不过 Jedis 实例是线程不安全的,多线程环境下得基于连接池来用。
• Lettuce:基于 Netty 实现,支持同步、异步和响应式编程方式,而且线程安全。还支持 Redis 的哨兵模式、集群模式和管道模式。
• Redisson:基于 Redis 实现的分布式、可伸缩的 Java 数据结构集合。有 Map、Queue、Lock、Semaphore、AtomicLong 这些强大功能。
• java-redis-client:一个很简单但很完整的 Java 客户端,不到 200 行代码,还没有依赖。
• vertx-redis-client:提供了异步 API 来和 Redis 数据结构服务器交互~
2、SpringDataRedis快速入门
2.1 什么是SpringDataRedis
SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,官网地址:https://spring.io/projects/spring-data-redis 。
• 提供了对不同Redis客户端的整合(Lettuce和Jedis)
• 提供了RedisTemplate统一API来操作Redis
• 支持Redis的发布订阅模型
• 支持Redis哨兵和Redis集群
• 支持基于Lettuce的响应式编程
• 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
• 支持基于Redis的JDKCollection实现
2.2 RedisTemplate工具类
SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:
API 返回值类型 说明
redisTemplate.opsForValue() ValueOperations 操作String类型数据
redisTemplate.opsForHash() sHashOperation 操作Hash类型数据
redisTemplate.opsForList() ListOperations 操作List类型数据
redisTemplate.opsForSet() SetOperations 操作Set类型数据
redisTemplate.opsForZSet() ZSetOperations 操作SortedSet类型数据
redisTemplate 通用的命令
API | 返回值类型 | 说明 |
---|---|---|
redisTemplate.opsForValue() | ValueOperations | 操作String类型数据 |
redisTemplate.opsForHash() | HashOperations | 操作Hash类型数据 |
redisTemplate.opsForList() | ListOperations | 操作List类型数据 |
redisTemplate.opsForSet() | SetOperations | 操作Set类型数据 |
redisTemplate.opsForZSet() | ZSetOperations | 操作SortedSet类型数据 |
redisTemplate | 通用的命令 |
2.2.1 自定义序列化
RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化。
JDK序列化的缺点:
- 可读性差
- 内存占用较大
因此,我们可以自定义RedisTemplate的序列化方式,代码如下
编写一个配置类:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
// 创建RedisTemplate对象
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 设置连接工厂
template.setConnectionFactory(connectionFactory);
// 创建JSON序列化工具
GenericJackson2JsonRedisSerializer jsonRedisSerializer =
new GenericJackson2JsonRedisSerializer();
// 设置Key的序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
// 设置Value的序列化
template.setValueSerializer(jsonRedisSerializer);
template.setHashValueSerializer(jsonRedisSerializer);
// 返回
return template;
}
}
这里采用了JSON序列化来代替默认的JDK序列化方式,将Java对象自动的序列化为JSON字符串,并且查询时能自动把JSON反序列化为Java对象。不过,其中记录了序列化时对应的class名称,目的是为了查询时实现自动反序列化。
2.3 StringRedisTemplate
Spring 默认提供了一个 StringRedisTemplate 类,它的 key 和 value 的序列化方式默认就是 String 方式。省去了我们自定义 RedisTemplate 的过程:
@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.writeValueAsString(user);
// 写入一条数据到redis
stringRedisTemplate.opsForValue().set("user:200", json);
// 读取数据
String val = stringRedisTemplate.opsForValue().get("user:200");
// 反序列化
User user1 = mapper.readValue(val, User.class);
System.out.println("user1 = " + user1);
}
这里通过 StringRedisTemplate 实现了对象的存储和读取,借助 JSON 工具来做序列化和反序列化,很方便呢~
2.4 小结
RedisTemplate的两种序列化实践方案
方案一:
1. 自定义RedisTemplate
2. 修改RedisTemplate的序列化器为GenericJackson2JsonRedisSerializer
方案二:
1. 使用StringRedisTemplate
2. 写入Redis时,手动把对象序列化为JSON
3. 读取Redis时,手动把读取到的JSON反序列化为对象