一、默认序列化器
序列化器:RedisTemplate的默认序列化器是JdkSerializationRedisSerializer
可以通过查看RedisTemplate源码查证
数据转换:该序列化器会将数据序列化成对象,在redis中是以二进制的方式进行存储的。
注意:要保存的数据对象必须要实现Serializable,否则会提示没有序列化。
优点: 可以保存任意Java对象,并且序列化后的数据体积相对较小。
缺点: 由于以二进制方式存储,所以数据的可读性非常差。且序列化和反序列化过程相对较慢。
假设我们要存储一组数据,key为"name",value为"橘生淮南",在Java中代码如下:
redisTemplate.opsForValue().set("name","橘生淮南");
/*
* //这里的redisTemplate在类中已经进行自动装配
* @Autowired
* private RedisTemplate redisTemplate;
*/
运行后我们查看存入数据库的内容
可见,默认序列化器对key和value都使用了二进制进行存储,可读性非常差。因此,想要有较好的可读性,就必须更改它的序列化方式。
另外,RedisTemplate选用JdkSerializationRedisSerializer作为默认序列化器,并不是因为它是最优秀的序列化器,而是它具有一定的通用性和兼容性,可以适应大部分场景的需求。优缺点上面已经提到了,不再赘述。
二、可选序列化器
同样,通过查阅源码,可以得到支持的所有序列化器,如下:
这里只讨论比较常用的两个序列化器:
①GenericJackson2JsonRedisSerializer: 将数据序列化成json
我们可以通过配置RedisTemplate对序列化器进行配置:
@Configuration
@Slf4j
public class RedisConfiguration {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
log.info("开始创建redis模板对象...");
//创建Template
RedisTemplate<String,Object> redisTemplate = new RedisTemplate();
//设置redis的连接工厂对象
redisTemplate.setConnectionFactory(redisConnectionFactory);
/*
注:当前配置类不是必须的,因为 Spring Boot 框架会自动装配 RedisTemplate 对象,
但是默认的key序列化器和value序列化器都是JdkSerializationRedisSerializer,
默认序列化器导致存到Redis中的数据和原始数据有差别(可读性差),
故设置为需要修改序列化器。
这里使用StringRedisSerializer作为key的序列化器,转为String存储。
使用GenericJackson2JsonRedisSerializer作为value的序列化器,转为json对象存储。
*/
//设置redis key的序列化器
redisTemplate.setKeySerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
//设置redis value的序列化器
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
log.info("redis模板对象创建完成...");
return redisTemplate;
}
}
这里对key和value都使用了GenericJackson2JsonRedisSerializer进行序列化。
1.写入文本数据
同样运行默认序列化器中给出的代码写入数据。
可以发现,key和value的可读性得到了保证,但key的两侧出现了双引号,虽不影响读取,但会占用一定的空间,对大量数据的情况造成不必要的开销,因此,推荐对key使用第二种序列化方式,即StringRedisSerializer,将key转换为String进行存储。除此之外,并没有太多的问题。
修改key的序列化器代码如下:
//设置redis key的序列化器
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
再次运行代码,redis中存储的key就不再带有双引号了。
2.写入对象数据
首先构造一个实体类UserVO,用于稍后作为对象传输。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserVO {
private Integer id;
private String username;
}
我们修改存入redis缓存代码,新建一个UserVO对象并存入。
//构造对象
UserVO userVO =new UserVO(1,"橘生淮南");
//设置redis缓存
redisTemplate.opsForValue().set("user",userVO);
存储结果如下:
可以看到,我们的UserVO对象成功存入了Redis中。
但我们可以发现,存入的数据中多了一条名为**"@class"的数据**,这条数据实际上是我们传入的对象的类的字节码,该字节码将会用于反序列化操作,如果不存储该字节码,序列化器在反序列化的时候就不知道这条数据对应的是哪个类,也就无法转换为原本的对象。
同样的,我们也可以发现,对于我们给出的这个对象,其字节码的长度实际上比我要存储的数据的长度还要长,或者说,字节码占用的空间比较大,对于大量数据的情况下,其开销较大。因此,为了节省空间,我们可以采用第二种序列化方式StringRedisSerializer对对象转化为字符串的形式进行存储。
②StringRedisSerializer:将数据序列化成字符串
通过StringRedisSerializer序列化器对对象进行存储,就是单纯的存储字符串,其要求传入的数据类型均为String类型。这就带来了一个问题,不论是序列化还是反序列化都将无法自动完成,必须要我们手动进行。
在Spring中,默认提供了一个名为StringRedisTemplate的类,其key和value的默认序列化方式就是String,因此我们直接使用自动装配就能使用了,无需再配置RedisTemplate。(即可以删除上面提到的RedisConfiguration了)
自动装配:
//装配String序列化器的redis
@Autowired
private StringRedisTemplate stringRedisTemplate;
存储数据的代码:
//构造对象
UserVO userVO =new UserVO(1,"橘生淮南");
//手动序列化为json
String userVoStr = JSON.toJSONString(userVO);//import com.alibaba.fastjson.JSON;
//设置redis缓存
stringRedisTemplate.opsForValue().set("user",userVoStr);
再次查看redis中的数据:
可以发现此时存储的数据已经不存在字节码了,达到了我们想要的效果。
我们从redis中读取user的值:
//取回redis缓存
String user = stringRedisTemplate.opsForValue().get("user");
//手动反序列化为对象
UserVO object = JSON.parseObject(user, UserVO.class);
System.out.println(object);
可以看到,数据均正常输出。
三、总结
综上,建议对key和value都使用StringRedisSerializer序列化器(通过StringRedisTemplate自动装配)进行处理,并手动实现数据的序列化与反序列化。