spring boot集成RedisTemplate,无法使用increment方法。

  在使用RedisTemplate时,某些场景调用redis的自增函数,对redis的某个缓存值自增加一。

    @Resource
    private RedisTemplate redisTemplate;

    @Test
    void contextLoads() {

        ValueOperations valueOperations = redisTemplate.opsForValue();

        valueOperations.set("k", 1);
        System.out.println(valueOperations.get("k"));
        valueOperations.increment("k");
        System.out.println(valueOperations.get("k"));
    }

   但是运行上面代码,会报一下错误:

org.springframework.data.redis.RedisSystemException: Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR value is not an integer or out of range

	at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:54)
	at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:52)
	at org.springframework.data.redis.connection.lettuce.LettuceExceptionConverter.convert(LettuceExceptionConverter.java:41)

           异常原因是ERR value is not an integer or out of range,由于k已经设置为1,那么肯定是redis里存储的value的值不是int类型。使用redis的可视化工具查看,存储数据如下:

          

          可以断定由于RedisTemplate的序列化后的格式导致。打开RedisTemplate,在InitializingBean接口的afterPropertiesSet方法中,默认序列化类是JdkSerializationRedisSerializer。

          

           JdkSerializationRedisSerializer 使用SerializingConverter对象转字节数组的转换器,将1序列化为上图的string值,导致redis无法对其自增自减。转换器底层序列化代码:

public interface Serializer<T> {

	/**
	 * Write an object of type T to the given OutputStream.
	 * <p>Note: Implementations should not close the given OutputStream
	 * (or any decorators of that OutputStream) but rather leave this up
	 * to the caller.
	 * @param object the object to serialize
	 * @param outputStream the output stream
	 * @throws IOException in case of errors writing to the stream
	 */
	void serialize(T object, OutputStream outputStream) throws IOException;

	/**
	 * Turn an object of type T into a serialized byte array.
	 * @param object the object to serialize
	 * @return the resulting byte array
	 * @throws IOException in case of serialization failure
	 * @since 5.2.7
	 */
	default byte[] serializeToByteArray(T object) throws IOException {
		ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
		serialize(object, out);
		return out.toByteArray();
	}

}

  

解决方法:

       修改RedisTemplate的值序列化类,将序列化类从jdk序列化改为redis通用序列化类GenericToStringSerializer。

       

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        // 1.创建 redisTemplate 模版
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        // 2.关联 redisConnectionFactory
        template.setConnectionFactory(redisConnectionFactory);
        // 3.设置 value 的转化格式和 key 的转化格式
        template.setValueSerializer(new GenericToStringSerializer<>(Object.class));
        template.setKeySerializer(new StringRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }

}

            GenericToStringSerializer在处理数字类型的时候,使用了ObjectToStringConverter的toString方法,将integer转为string,再使用getBytes转为字节数组。

            

final class ObjectToStringConverter implements Converter<Object, String> {

	@Override
	public String convert(Object source) {
		return source.toString();
	}

}
  public byte[] serialize(@Nullable T object) {
        if (object == null) {
            return null;
        } else {
            String string = (String)this.converter.convert(object, String.class);
            return string.getBytes(this.charset);
        }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值