前端時間新項目使用SpringBoot的RedisTemplate遇到一個問題,先簡單描述一下問題:不同項目之間redis共用一個,但是我們新項目讀不到老項目存儲的緩存。新項目搭建的時候沒有跟老項目使用同一個core包里的redisutils工具類,老項目使用的是jedis對象來操作redis,新項目使用了springboot封裝的redistemplate,代碼上存在差異所以出現問題也就很正常,先來看一下新項目里對redistemplate的使用:(截取一個方法為例)
現象:
可以看出來工具直接注入spring容器中的redistemplate,沒有指定泛型,在使用的時候通過key的泛型使用的是Serializable,value的泛型是value,從泛型能看出來key跟泛型有一定關系,下面就來驗證一下為什么取不到值。我們先往redis里存儲一個緩存以字符串為例:
寫一個junit測試
測試取緩存
通過結果發現沒有取到值,反過來通過測試方法存一下緩存,再看我們存的是一個什么值
通過結果發現我們存進去的key是redistemplate-test,但是redis實際存進去的key卻是\xac\xed\x00\x05t\x00\x12redistemplate-test,同理,我們取緩存的時候前面也會自動加上一串看不懂的東西,所以取值的時候肯定也取不出來。做項目的時候時間比較緊,用了其他同事的代碼保證項目上線,上線后才回過頭去看取不到值的原因,其實同事的代碼也很簡單,只是在使用redistemplate的時候指定了泛型為string,就可以取到值了,其實也可以使用StringRedisTemplate來操作,但是StringRedisTemplate主要用來存儲字符串,它的泛型指定的是String。如果存入對象時,會報錯 :can not cast into String,所以我們就繼續修改這個工具,解決key值前面的字符串。
原因:
下面我們簡單的看一下redistemplate源碼
opsForValue方法會返回一個ValueOperations<K, V>,k跟v就是泛型,我們就是通過valueOps來get,set我們的值。這個方法會new一個DefaultValueOperations對象,傳入的template就是當前RedisTemplate對象,向下看:
有很多個RedisSerializer,默認都是null,當調用opsForValue方法時會傳入當前redistemplate對象,以keySerializer為例,它默認為null,如果等於null就被賦值dafaultSerializer,默認dafaultSerializer也為空,最終keySerializer就被賦值為JdkSerializationRedisSerializer,所以沒有設置序列化方式的時候redistemplate使用的序列化方式為JdkSerializationRedisSerializer,所以我們存入key前面會帶上一串東西,而StringRedisTemplate使用的是 StringRedisSerializer,序列化的方式不一樣,所以使用的時候key就不會出現一串字符串。
解決方案:
簡單了解原因后,現在就來解決這個問題,解決問題的方法就是設置序列化方式
這樣解決了上面的問題。問題倒不難,只是自己以前沒有遇到過,不知道這個方法是同事從網上直接復制的還是同事自己寫的,只能說復制的時候不夠嚴謹,沒有考慮到項目的實際情況,這個問題其實只要拿出一塊時間去看看代碼,查查資料就能解決,所以遇到問題的時候一定要找到原因去解決問題,而不是把問題隱藏掉。