Spring-data-redis序列化⽅案(⼀)
JdkSerializationRedisSerializer 和 GenericFastJsonRedisSerializer
源码对⽐
性能对⽐——插⼊
优缺点总结
笔者在上篇中使⽤了阿⾥巴巴的fastjson的 GenericFastJsonRedisSerializer序列化⽅案貌似解决了乱码问题,但笔者之后再次排查,发现乱码问题和序列化⽅案并没有直接关系。想要知道答案,那么请读完此篇⽂章。
RedisSerializer提供了九种序列化⽅案,分别为:
Spring-data-redis fastjson
ByteArrayRedisSerializer FastJsonRedisSerializer
GenericJackson2JsonRedisSerializer GenericFastJsonRedisSerializer
GenericToStringSerializer
Jackson2JsonRedisSerializer
JdkSerializationRedisSerializer
OxmSerializer
StringRedisSerializer
Redis在储存数据时需要将数据转化为byte数组进⾏存储,这⼀点需要提前说明,接下来这⼀篇⽂章只谈 JdkSerializationRedisSerializer 和GenericFastJsonRedisSerializer这两种序列化⽅案的相关问题。
源码对⽐
JdkSerializationRedisSerializerfastjson常用方法
作为默认的序列化⽅案,JdkSerializationRedisSerializer 有两个属性:
private final Converter<Object,byte[]> serializer;
private final Converter<byte[], Object> deserializer;
想来读者已经猜到了它⼤致的作⽤,点进Converter中去看注释的解释:
import org.springframework.lang.Nullable;
/**
* A converter converts a source object of type {@code S} to a target of type {@code T}.
*
* <p>Implementations of this interface are thread-safe and can be shared.
*
* <p>Implementations may additionally implement {@link ConditionalConverter}.
*
* @author Keith Donald
* @since 3.0
* @param <S> the source type
* @param <T> the target type
*/
@FunctionalInterface
public interface Converter<S, T>{
/**
* Convert the source object of type {@code S} to target type {@code T}.
* @param source the source object to convert, which must be an instance of {@code S} (never {@code null})
* @return the converted object, which must be an instance of {@code T} (potentially {@code null})
* @throws IllegalArgumentException if the source cannot be converted to the desired target type
*/
@Nullable
T convert(S source);
}
⼤致意思就是将S型的源数据转化为T型的数据。所以现在就好理解了,JdkSerializationRedisSerializer 中的两个属性:serializer的作⽤为将Object转化为byte数组,⽽deserializer 则相反,将byte数组转化为Object。
最重要的就是序列化和反序列化的实现了,且看源码:
public Object deserialize(@Nullable byte[] bytes){
if(SerializationUtils.isEmpty(bytes)){
return null;
}else{
try{
return vert(bytes);
}catch(Exception var3){
throw new SerializationException("Cannot deserialize", var3);
}
}
}
public byte[]serialize(@Nullable Object object){
if(object == null){
return SerializationUtils.EMPTY_ARRAY;
}else{
try{
return(byte[])vert(object);
}catch(Exception var3){
throw new SerializationException("Cannot serialize", var3);
}
}
}
源码也很好理解,序列化⽅法⼊参为⼀个Object对象,若此Object为空则返回null,不为空就调⽤Converter<Object, byte[]>的convert进⾏类型转化序列化完成。反序列化也是⼀个道理。它的底层还是通过调⽤JDK的IO操作ObjectInputStream和ObjectOutputStream类实
现POJO类的序列化和反序列化。
GenericFastJsonRedisSerializer
此序列化⽅案是很受欢迎的,甚⾄称之为 “万能” 的序列化⽅案,那么它到底如何实现的?
public class GenericFastJsonRedisSerializer implements RedisSerializer<Object> {
private final static ParserConfig defaultRedisConfig = new ParserConfig();
static { defaultRedisConfig.setAutoTypeSupport(true);}
@Override
public byte[] serialize(Object object) throws SerializationException {
if (object == null) {
return new byte[0];
}
try {
JSONBytes(object, SerializerFeature.WriteClassName);
} catch (Exception ex) {
throw new SerializationException("Could not serialize: " + ex.getMessage(), ex);
}
}
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length == 0) {
return null;
}
try {
return JSON.parseObject(new String(bytes, IOUtils.UTF8), Object.class, defaultRedisConfig);
} catch (Exception ex) {
throw new SerializationException("Could not deserialize: " + ex.getMessage(), ex);
}
}
}
它的序列化为将Object对象转化为JSON型的byte数组存储Redis,反序列化时将byte数组进⾏UTF-8编码转化为Object类输出。性能对⽐——插⼊
我使⽤的POJO类为:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserModel{
/**
* 主键
*/
private Integer id;
/**
* ⽤户账号
*/
private String userId;
/**
* ⽤户姓名
*/
private String userName;
/
**
* ⽤户证件号码
*/
private String idNumber;
/**
* ⽤户邮箱
*/
private String email;
}
通过控制Redis序列化⽅案进⾏插⼊对⽐:
@Configuration
public class RedisConfig {
/**
* redisTemplate 序列化使⽤的jdkSerializeable, 存储⼆进制字节码, 所以⾃定义序列化类
* @param redisConnectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object>redisTemplate(RedisConnectionFactory redisConnectionFactory){ RedisTemplate<String, Object> redisTemplate =new RedisTemplate<>();
// 使⽤Jackson2JsonRedisSerialize 替换默认序列化
// GenericFastJsonRedisSerializer redisSerializer = new GenericFastJsonRedisSerializer();
JdkSerializationRedisSerializer redisSerializer =new JdkSerializationRedisSerializer();
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setValueSerializer(redisSerializer);
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
redisTemplate.setHashValueSerializer(redisSerializer);
redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}
}
测试代码:
class RedisDemoApplicationTests {
@Autowired
private RedisUtils redisUtils;
@Test
void contextLoads(){
StopWatch sw =new StopWatch("StringRedisSerializer");
AtomicInteger number =new AtomicInteger(1);
List<UserModel> userModels =userModelList(1000000);
sw.start("StringRedisSerializer");
userModels.stream().forEach(userModel ->{
String key ="user_"+ number;
redisUtils.set(key,userModel);
});
sw.stop();
System.out.println(sw.prettyPrint());
}
/**
* @Method: userModelList
* @Description: 获取⽤户数据
* @param size ⽤户数量
* @Return: java.util.List&disdemo.del.UserModel>
* @Author: wangdehonga
* @Date 2020/9/9 13:44
* @Version: 1.0
*/
List<UserModel> userModelList (int size){
// 封装⽤户结果集
List<UserModel> userModels =new ArrayList<>(size);
// 主键
int ids =1;
// ⽤户账号
String[] userIds = RandomUtils.randomNumbers(8,size,false);
// ⽤户姓名
String[] userNames = RandomUtils.randomUserName(size);
// ⽤户证件号码
String[] idNumbers = RandomUtils.randomIDNumber(size);
// ⽤户邮箱
String[] emails = RandomUtils.randomEmail(size);
// 组装⽤户数据
while(ids <= size){
userModels.add(new UserModel(ids, userIds[ids-1], userNames[ids-1], idNumbers[ids-1], emails[ids-1]));
ids ++;
}
return userModels;
}
}
JdkSerializationRedisSerializer 测试结果:
数据量(万)耗时(s)占⽤Redis服务器内存(M)117.0219 4.00
10175.240.00
50811.69225.00
1001776.54390.00
Redis结构:
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论