springboot的RedisTemplate序列化问题

spring-data-redis提供了多种serializer策略,默认有七种,当然还可以自定义序列化和反序列化方式。

  • JdkSerializationRedisSerializer
  • StringRedisSerializer
  • JacksonJsonRedisSerializer
  • Jackson2JsonRedisSerializer
  • GenericJackson2JsonRedisSerializer
  • GenericToStringSerializer
  • OxmSerializer
//RedisTemplate默认的序列化方式为JdkSerializationRedisSerializer

private RedisSerializer<?> defaultSerializer = new JdkSerializationRedisSerializer();

public void afterPropertiesSet() {
		super.afterPropertiesSet();
		boolean defaultUsed = false;

		if (enableDefaultSerializer) {
			if (keySerializer == null) {
				keySerializer = defaultSerializer;
				defaultUsed = true;
			}
			if (valueSerializer == null) {
				valueSerializer = defaultSerializer;
				defaultUsed = true;
			}
			if (hashKeySerializer == null) {
				hashKeySerializer = defaultSerializer;
				defaultUsed = true;
			}
			if (hashValueSerializer == null) {
				hashValueSerializer = defaultSerializer;
				defaultUsed = true;
			}
		}
	}

一、先看序列化和反序列化的问题

//要序列化的对象
public class Test {
    private String id;
    private String name;
    public Test(String id,String name){
	    this.id = id;
	    this.name = name;
}

Test test = new Test("123","zhangshan");

序列化过程:

以key-value键值对为例:

redisTemplate.opsForValue.set("123",test)

//key的序列化
byte[] rawKey(Object key) {
		Assert.notNull(key, "non null key required");
		if (keySerializer() == null && key instanceof byte[]) {
			return (byte[]) key;
		}
		return keySerializer().serialize(key);
	}
	
//value的序列化
byte[] rawValue(Object value) {
		if (valueSerializer() == null && value instanceof byte[]) {
			return (byte[]) value;
		}
		return valueSerializer().serialize(value);
	}
//RedisTemplate默认的序列化方式DefaultSerializer,把对象写入ObjectOutputStream
public void serialize(Object object, OutputStream outputStream) throws IOException {
		if (!(object instanceof Serializable)) {
			throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
					"but received an object of type [" + object.getClass().getName() + "]");
		}
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
		objectOutputStream.writeObject(object);
		objectOutputStream.flush();
	}

//Jackson2JsonRedisSerializer的序列化方式
public byte[] serialize(Object source) throws SerializationException {
		if (source == null) {
			return EMPTY_ARRAY;
		}
		try {
			return mapper.writeValueAsBytes(source);
		} catch (JsonProcessingException e) {
			throw new SerializationException("Could not write JSON: " + e.getMessage(), e);
		}
	}

反序列化过程:

redisTemplate.opsForValue.get("123")

//value反序列化
	V deserializeValue(byte[] value) {
		if (valueSerializer() == null) {
			return (V) value;
		}
		return (V) valueSerializer().deserialize(value);
	}
//RedisTemplate默认的反序列化方式DefaultDeserializer,从ObjectInputStream中读取对象。
public Object deserialize(InputStream inputStream) throws IOException {
		ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream, this.classLoader);
		try {
			return objectInputStream.readObject();
		}
		catch (ClassNotFoundException ex) {
			throw new NestedIOException("Failed to deserialize object type", ex);
		}
	}

//Jackson2JsonRedisSerializer的反序列化方式
public <T> T deserialize(byte[] source, Class<T> type) throws SerializationException {

		Assert.notNull(type,
				"Deserialization type must not be null! Pleaes provide Object.class to make use of Jackson2 default typing.");
		if (isEmpty(source)) {
			return null;
		}
		try {
			return mapper.readValue(source, type);
		} catch (Exception ex) {
			throw new SerializationException("Could not read JSON: " + ex.getMessage(), ex);
		}
	}

跟加密和解密一样,序列化和反序列化时的方式也必须是对应的。用JdkSerializationRedisSerializer序列化后,再用Jackson2JsonRedisSerializer反序列化肯定会报错或取不到值。

二、RedisTemplate序列化需要注意的问题

1、很多微服务之间会用redis作分布式缓存。如果ServiceA用默认的序列化方式,而ServiceB用Jackson2JsonRedisSerializer或者其他的序列化方式,就会出现ServiceA把值存到redis缓存中,而ServiceB从redis缓存中取不到值的问题。最好的方式是各个微服务之间唯一确定好一种序列化方式,统一规范,统一配置。
2、万一出现了两个服务之间配置RedisTemplate的序列化方式和反序列化方式不一样导致从缓存中取不到值时,可以局部new一个新的RedisTemplate,设置相对应的反序列化方式,做下兼容处理。比如ServiceA的序列化方式为默认的,ServiceB的全局序列化方式为Jackson2JsonRedisSerializer,ServiceB可以在从缓存中取值时局部重新new一个RedisTemplate,设置序列化方式为默认的,然后用局部redisTemplate从缓存中取值。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot 中的 RedisTemplate 是一个用于操作 Redis 数据库的高级模板类。它提供了一组方法,可以方便地执行常见的 Redis 操作,如存储、检索和删除数据。 使用 RedisTemplate 需要先配置 Redis 的连接信息,包括主机、端口、密码等。可以通过在 application.properties(或 application.yml)文件中设置相应的属性来配置 Redis 连接信息。 接下来,可以通过自动装配的方式将 RedisTemplate 注入到需要使用 Redis 的类中。然后就可以使用 RedisTemplate 的方法来执行对应的 Redis 操作了,比如: - 存储数据:可以使用 opsForValue() 方法来获取 ValueOperations 对象,然后通过 set() 方法存储键值对。 - 检索数据:可以使用 opsForValue() 方法来获取 ValueOperations 对象,然后通过 get() 方法检索键对应的值。 - 删除数据:可以使用 delete() 方法删除指定的键。 除了上述常见操作外,RedisTemplate 还提供了其他一些方法,例如对列表、集合、有序集合等数据结构进行操作的方法。 需要注意的是,RedisTemplate 是一个泛型类,可以通过设置泛型参数来指定键和值的类型。默认情况下,键和值都被序列化为字节数组进行存储,但也可以自定义序列化器来支持其他类型的对象。 总之,RedisTemplate 提供了一种方便、简洁的方式来操作 Redis 数据库,使得在 Spring Boot 项目中使用 Redis 变得更加容易和高效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值