1. 程式人生 > >【Redis錯誤】-Redis存、取異常之序列化問題

【Redis錯誤】-Redis存、取異常之序列化問題

問題場景:因業務不斷擴充套件,實體類有較多的重複欄位,故要優化資料結構,從而優化系統性能,增加程式碼的可複用性。測試環境和預生產都沒有問題,到生產有部分欄位取不到數值,關了快取開關後,發現業務程式碼正常了,開啟快取就會出現各種null異常

問題分析:Redis存進去的日誌正常,去的時候要麼少欄位,要麼整個結果集為null,本地測試,直接存完就取發現問題依舊如此。對比儲存String型別,發現Redis是可以正常存取的,那問題就出現在我們重構的實體類中,最後排查到新的實體類未被序列話造成的,如圖:

少實現了Serializable介面。

實現Serializable介面的意義:

對例項物件的狀態(State 物件屬性而不包括物件方法)進行通用編碼(如格式化的位元組碼)並儲存,以保證物件的完整性和可傳遞性,使其在不同時間或不同平臺的JVM之間共享例項物件。

檢視Redis原始碼:

public class RedisCache {

    private RedisInterface redisInterface;

    public <T> T get(String key) {
        byte[] data = redisInterface.get(SerializationUtils.serialize(key));
        return (T) SerializationUtils.deserialize(data);
    }

    public void set(String key, final Object value) {
        redisInterface.set(SerializationUtils.serialize(key), SerializationUtils.serialize(value));
    }

    public void set(String key, Object value, int expire) {
        set(key, value);
        expire(key, expire);
    }

    public void expire(String key, int expire) {
        redisInterface.expire(SerializationUtils.serialize(key), expire);
    }

    public void evict(String key) {
        redisInterface.del(SerializationUtils.serialize(key));
    }


    public void setRedisInterface(RedisInterface redisInterface) {
        this.redisInterface = redisInterface;
    }
}

再看其抽象工具類:

public abstract class SerializationUtils {

	/**
	 * Serialize the given object to a byte array.
	 * @param object the object to serialize
	 * @return an array of bytes representing the object in a portable fashion
	 */
	public static byte[] serialize(Object object) {
		if (object == null) {
			return null;
		}
		ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
		try {
			ObjectOutputStream oos = new ObjectOutputStream(baos);
			oos.writeObject(object);
			oos.flush();
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex);
		}
		return baos.toByteArray();
	}

	/**
	 * Deserialize the byte array into an object.
	 * @param bytes a serialized object
	 * @return the result of deserializing the bytes
	 */
	public static Object deserialize(byte[] bytes) {
		if (bytes == null) {
			return null;
		}
		try {
			ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
			return ois.readObject();
		}
		catch (IOException ex) {
			throw new IllegalArgumentException("Failed to deserialize object", ex);
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException("Failed to deserialize object type", ex);
		}
	}

}

    所以未曾實現序列化的實體類是無法被序列化到Redis中介軟體中的。

    這也是此次問題的原因根本,記此筆記警示自己,提請他人。