背景
記錄在redis中的多語言緩存,突然發現取值無法正常解析,加日志后發現,從redis取出來的值,有些在正常值的前面多了很多 \u0000
,有些值好像是覆蓋原有值但沒覆蓋全的樣子 {"key":"new Value"}lue"}
,導致在解析數據是報錯。
定位問題
通過記錄日志,發現在向redis中添加值時,值還是正常的,再取出來,就會發生這些變化,於是懷疑問題出在set方法上。
排查代碼,發現代碼中使用了兩種set方法。
set(k, v, expireTime);
set(k, v, expireTime,TimeUnit.SECONDS);
這兩個方法乍一看,好像是少了個設置超時時間的單位,但實際上這兩個方法的功能完全不一樣。
void set(K key, V value, long offset)
這個三參的方法de Jdoc如下,用指定的值,追加覆蓋原有內容,追加覆蓋的位置由offset確定。
Overwrite parts of key starting at the specified offset with given value.
Params:
key – must not be null.
value –
offset –
需要注意的是,如果原有內容長度不夠,則會使用\u0000
填充到足夠的長度。
比如:現有鍵值對 {"test":"ABCD"}
, 使用set("test","12",10)
,會有以下操作
ABCD不足10,所以使用 \u0000
填充到長度10,即 ABCD\u0000\u0000\u0000\u0000\u0000\u0000
,
然后追加覆蓋12
, 最后的值為ABCD\u0000\u0000\u0000\u0000\u0000\u000012
。
這個在調試時才會看到,控制台打印出來的結果是ABCD12
。
void set(K key, V value, long timeout, TimeUnit unit)
這個方法才是正確的保存鍵值對,並設置過期時間。
Set the value and expiration timeout for key.
Params:
key – must not be null.
value – must not be null.
timeout – the key expiration timeout.
unit – must not be null.
總結
使用重載方法時,需要確認方法每個參數的含義,確認方法的功能,雖然有些參數類型是一樣的,但實現的功能也會千差萬別。 切記切記。