一:SpringData模块简介
SpringData是Spring中数据操作模块,包含了对于各种数据库的集成,其中对于Redis的集成模块就叫做SpringDataRedis
二:SpringDataRedis简介
1:SpringDataRedis作用
1:提供了对于不同Redis的Java客户端整合(Lettuce和Jedis)
2:提供了RedisTemplate统一API来操作Redis
3:支持Redis的发布订阅模型
4:支持Redis的哨兵和Redis集群
5:支持基于Lettuce的响应式编程
6:支持基于JDK、JSON、字符串、Spring对象的序列化和反序列化
7:支持基于Redis的JDKCollection实现。
2:SpringDataRedis说明
Spring从来不会重复造轮子,都是集成整合对其他优秀工具的整合。底层整合了Jedis和Lettuce并提供了统一的API,SpringDataRedis提供了统一操作Redis的API叫做:RedisTemplate,底层的实现实际上是由Lettuce和Jedis实现的。
值得一提的是响应式编程这块,如果要是想使用Spring的WebFlux做响应式编程的话,使用SpringDataRedis再好不过了。
Jedis当中我们进行set的时候,我们的value都是String或者字节数组,我们讲过Redis的数据的底层都是字节数据,现在如果要是由一个Java对象要存储,我们需要基于SpringDataRedis提供的序列化和反序列化功能来转成二进制数组(字节数组),然后将数据进行存取即可。
支持基于Redis的JDKCollection实现,我们基于Redis重新实现了这些集合。我们JDK原生的Collection是在一个虚拟机中,是一个进程中的。基于Redis实现的JDKCollection是分布式的是跨系统的。
SpringDataRedis核心就是RedisTemplate这里边封装了一系列的API
三:SpringDataRedis入门
1:RedisTemplate命令分组设计
Jedis客户端命令有上百个,Jedis当中一个命令与命令行客户端是基本上是一一对应的。RedisTemplate中对我们的命令是进行了分组的:
RedisTemplate当中的是一些通用的特殊的命令。
2:依赖引入
第一个是SpringBoot对于Redis的客户端也就是Jedis的整合。
第二个是连接池,不论是Jedis还是Lettuce也好,底层都是基于commons-pools连接池实现的。
第三个还需要引入一个JackSon的依赖,配置Redis值得序列化工具的时候使用。
2:创建一个SpringBoot项目
SpringBoot的自动装配的好处就是我们不用写编码了。直接将配置文件写入到SpringBoot的配置文件当中,就会自动有
1):基于配置自动装配
2):对象直接注入
对象也不用我们创建了,我们直接拿来用即可。直接在我们自己的业务代码中@Autowired即可
3):单元测试
3:RedisSerializer序列化工具
1):一个诡异的问题
问题:我们Redis-cli里边进行set name rose 之后,我们在RedisTemplate进行一个redisTemplate.opsForValue().set(“name”,“虎哥”);会发现在我们的Redis但中有两个key与name相关的键值对,一个是:
2):问题原因
这里边有两个与name相关的key,这是因为RedisTemplate当中接收的是Java对象,set可以接收任何类型的对象,帮我们把它转成Redis可以识别的数据结构进行存储。
3):RedisTemplate四个序列化器
Redis的set方法接收的参数不是String,而是Object将此转换成Redis可以处理的字节,这里边序列化使用的就是JDK提供的ObjectOutStream,RedisTemplate查看源码点击去之后,我们可以看到四个序列化器:
4):默认JDKRedisSerializer
四个序列化器会被相应的进行初始化。ObjectOutStream这个对象目的就是为了将对象写成字节,将字节存存入到Redis当中,这种可读性很差,我们明明存的是虎哥,但是get的时候不知道拿到是什么样的一串东西。另外就是我们的key也被序列化了,都不知道key是什么玩意。
另外就是占用内存较大,这些都可以从下图中看到:
所以说,我们希望我们写的是什么,就存的是什么,这样我们就需要改变RedisTemplate的默认的序列化方式了,不要用默认的了。
我们的key一般使用StringRedisSerializer(字符串转字节储存Redis直接getByte()即可,没必要序列化,只不过指定字符集即可)我们的value一般使用GenericJackson2JsonRedisSerializer将对象转换为JSON字符串(我们需要引入Jackson的依赖,SpringMVC会自动引入这个依赖的)。
RedisTemplate是支持我们修改上述序列化工具的,如下修改即可。
RedisConectionFactory这个对象不用我们字节创建,SpringBoot会帮我们自动创建和进行注入。
我们试一下,如果我们写入一个对象,会不会帮我们成功写入进去,并且写入的是我们期望的:
此序列化工具确实将User对象以JSON的形式在Redis当中进行存储,JSON中还有对应的对象的类型,这样我们get的时候可以将对象序列化回来,这是一个非常棒的现象。
4:StringRedisTemplate
这里边对象的类型信息,占用的内存信息甚至比我们的数据本身还要大。在一些超大型项目中,这是无法接收的。我们可不可以不存这些东西呢,答案是可以的。为了节省内存空间,我们通常不会使用JSON序列化器来处理value而是统一使用String序列化器,要求只能存储String类型的key和value,当我们要存储Java对象时,手动完成对象的序列化和反序列化。
这样做代码复杂了一丢丢,但是这样做节省了很大的内存空间,这里我们使用了两次手动的序列化和反序列化的操作,解决了这个问题。
本来我们实现上述这个事需要将RedisTemplate对象其中的四个序列化工具改为StringRedisSerializer,好消息是SpringDataRedis提供了这样的工具,那就是StringRedisTemplate,这个类key和vlaue的序列化方式默认就是String,省略了我们自定义RedisTemplate的过程。
这里边的mapper是类似于FastJson这样的工具。对象实体和JSON之间的互转。我们set和get的就是字符串本身。ObjectMapper是SpringMVC里边使用的默认的JSON处理工具,我们在这里使用它。
5:RedisTemplate的两种序列化实践方案
方案一:
1:自义定RedisTemplate
2:修改RedisTemplate的序列化为GenericJackSon2JsonRedisSerializer
方案二:
1:使用StringRedisTemplate
2:写入Redis时,手动把对象序列化为JSON
3:读取Redis事,手动把JSON序列化为对象。
四:StringRedisTemplate
redisTemplate.opsForValue().set("name","虎哥");
RedisTemplate中的set方法可以接收任何类型的参数,我们在这里放入的是Java对象ReidsTemplate这里使用JDK的序列化方式OutputStream将
上篇文章当中,我们已经学会了,如何字自定义Redis的序列化器,来实现全自动的JSON的序列化和反序列化,这样的话我们在RedisTemplateAPI中写入一个Java对象的时候,会自动帮我们写成一个JSON,读取的时候会自动将JSON反序列化成我们的Java对象,使用起来非常方便。
但是上述这种方式是有一点点问题的,就是他在他的序列化Json当中夹带了对象的类型。
类型内容占用的空间比我们的数据内容还要大,大量的空间被浪费了。但是这玩意,还必须得记录,否则反序列化的时候就没办法完了。
因此,为了节省空间,我们并不会使用JSON序列化器,而是统一使用String序列化器,要求只能存储String类型的key和value,当要存储Java对象的时候,手动完成对象的序列化和反序列化。
非常好的是SpringRedisTemplate默认使用的就是String序列化器