spring redistemplate中使用setHashValueSerializer的設置hash值序列化方法


筆者曾經對redis鍵值使用了不同類型的序列化方法

用過默認值、JdkSerializationRedisSerializer、StringRedisSerializer還用改以下自定類型的序列化工具類(據說這個比Spring RedisTemplate的序列化、反序列化快)

import com.dyuproject.protostuff.LinkedBuffer;
import com.dyuproject.protostuff.ProtostuffIOUtil;
import com.dyuproject.protostuff.Schema;
import com.dyuproject.protostuff.runtime.RuntimeSchema;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;

public class ProtostuffSerializer implements RedisSerializer<Object> {

    private boolean isEmpty(byte[] data) {
        return (data == null || data.length == 0);
    }

    private final Schema<ProtoWrapper> schema;

    private final ProtoWrapper wrapper;

    private final LinkedBuffer buffer;

    public ProtostuffSerializer() {
        this.wrapper = new ProtoWrapper();
        this.schema = RuntimeSchema.getSchema(ProtoWrapper.class);
        this.buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
    }

    @Override
    public byte[] serialize(Object t) throws SerializationException {
        if (t == null) {
            return new byte[0];
        }
        wrapper.data = t;
        try {
            return ProtostuffIOUtil.toByteArray(wrapper, schema, buffer);
        } finally {
            buffer.clear();
        }
    }

    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
        if (isEmpty(bytes)) {
            return null;
        }

        ProtoWrapper newMessage = schema.newMessage();
        ProtostuffIOUtil.mergeFrom(bytes, newMessage, schema);
        return newMessage.data;
    }

    private static class ProtoWrapper {

        public Object data;

    }
}

遇到過以下異常:

hash操作:java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String,然后這次又換另外一個Hash的序列化類

template.setHashValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));

序列化后的緩存如下:

 

 

因為上次使用ProtostuffSerializer對Hash值進行序列化,進行以下操作報錯了

HashOperations<String,String,T> hashOperations = redisTemplate.opsForHash();

        if(value instanceof Long || value instanceof Integer|| value instanceof Short||value instanceof Byte)
        {
            long longValue = ((Number) value).longValue();
            hashOperations.increment(key,field,longValue);
        }

        if(value instanceof Float ||value instanceof  Double)
        {
            double doubleValue = ((Number) value).doubleValue();
            Double returned = hashOperations.increment(key, field, -0.005);
        }
        return hashOperations;

報錯如下:io.lettuce.core.RedisCommandExecutionException: ERR hash value is not a valid float

,因為經過ProtostuffSerializer序列化的hash值會變形,編程、\X0A=\X5A\X43\XC格式的數據,進行數值運算報錯。

 

注意事項:redis端increment操作,只支持double和long,所以數據要進行相關轉換。

比如筆者代碼如下,就會報錯:

 

 public <T> T getCacheHashValue(String key, String field, Class<T> targetClass) {
        HashOperations<String,String,T> hashOperations = redisTemplate.opsForHash();
        return hashOperations.get(key, field);
    }

 

傳入

Float balance = cacheService.getCacheHashValue(cacheKey, "balance", Float.class);

報錯:

Caused by: java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Float

 

redisTemplate相關文章:

springboot項目中使用spring-data-Redis對map序列化時報錯

使用redisTemplate存儲數據,出現\xAC\xED\x00\x05t\x00

 參考:

Spring-data-redis @Cacheable java.lang.ClassCastException: java.util.HashMap cannot be cast to java.lang.String


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM