日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Redis遇到的那些坑

發布時間:2025/3/16 数据库 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Redis遇到的那些坑 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言


Redis 作為當前最流行的 NoSQL 之一,想必很多人都用過。

Redis 有五種常見的數據類型:string、list、hash、set、zset。講真,我以前只用過 Redis 的 string 類型。

由于業務需求,用到了 Redis 的集合 set。這不,一上來就踩到坑了。

前幾天有個需求提測,測試小哥提了個 bug,并給了我一個日志截圖:

?

問題排查

從堆棧信息定位到了項目的代碼,大致如下:

public?class?CityServiceprivate?void?setStatus(CityRequest?request)?{//?根據城市碼查詢城市信息Set<String>?cityList?=?cityService.findByCityCode(request.getCityCode());if?(CollectionUtils.isEmpty(cityList))?{return;}//?遍歷,做一些操作(報錯就在這這一行)for?(String?city?:?cityList)?{//?...}}//?一些無關的代碼... }

報錯的代碼就在 for 循環那一行。

這一行看起來似乎沒什么錯誤,跟 HashSet 和 String 轉換有什么關系呢?往前翻一翻 cityList 是怎么來的。

cityList 會根據城市碼查詢城市信息,這個方法有如下三步:

  • 從本地緩存查詢,若存在則直接返回;否則進行第二步。

  • 從 Redis 查詢,若存在,存入本地緩存并返回;否則進行第三步。

  • 從 MySQL 查詢,若存在,存入本地緩存和 Redis(set 類型)并返回;若不存在返回空。

  • 聯系報錯信息,再看這幾步的代碼,1、3 可能性較小;第二步因為之前沒有直接用過 set 這種數據結構,嫌疑較大。

    于是想先通過 Redis 客戶端看下緩存信息。

    這一看不當緊,更疑惑了:Redis 的 key/value 前面有類似\xAC\xED\x00\x05t\x00\x1B 的字符串(可能略有不同),而且還有亂碼。如圖:

    亂碼問題處理

    網上查了一番,原來是 spring-data-redis 的 RedisTemplate 序列化的問題。

    RedisTemplate 的默認配置如下:

    public?class?RedisAutoConfiguration?{@Bean@ConditionalOnMissingBean(name?=?"redisTemplate")public?RedisTemplate<Object,?Object>?redisTemplate(RedisConnectionFactory?redisConnectionFactory)throws?UnknownHostException?{RedisTemplate<Object,?Object>?template?=?new?RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory);return?template;} }

    RedisTemplate 在操作 Redis 時默認使用 JdkSerializationRedisSerializer 來進行序列化的。

    對于這個問題,修改下配置就可以了,示例代碼如下:

    @Configuration @AutoConfigureAfter(RedisAutoConfiguration.class) public?class?RedisConfig?{@Beanpublic?RedisTemplate<String,?Object>?redisTemplate(RedisConnectionFactory?redisConnectionFactory)?{RedisTemplate<String,?Object>?redisTemplate?=?new?RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);//?使用?Jackson2JsonRedisSerialize?替換默認序列化Jackson2JsonRedisSerializer?jackson2JsonRedisSerializer?=?new?Jackson2JsonRedisSerializer<>(Object.class);ObjectMapper?objectMapper?=?new?ObjectMapper();objectMapper.setVisibility(PropertyAccessor.ALL,?JsonAutoDetect.Visibility.ANY);objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,?false);jackson2JsonRedisSerializer.setObjectMapper(objectMapper);//?設置?key/value?的序列化規則redisTemplate.setKeySerializer(new?StringRedisSerializer());redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);redisTemplate.setHashKeySerializer(new?StringRedisSerializer());redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);redisTemplate.afterPropertiesSet();return?redisTemplate;} }

    這個配置改過之后,亂碼的情況就沒了。

    類型轉換問題

    繼續跟進前面的類型轉換問題。

    通過客戶端查看 Redis 的值,如下:

    這是什么鬼?明顯不對勁兒啊!

    我們想存儲的是 set 類型,正常應該是三條數據,這里怎么只有一條?

    想了想應該是向 Redis 存儲值的時候有什么問題,于是翻到代碼看了看怎么存的:

    public?class?CityService?{public?Set<String>?findCityByCode(String?cityCode)?{//?...//?查詢MySQLList<CityDO>?cityDoList?=?cityRepository.findByCityCode(cityCode);//?封裝數據Set<String>?cityList?=?new?HashSet<>();cityDoList.forEach(record?->?{String?city?=?String.format("%s-%s",?record.getType(),?record.getCity());cityList.add(city);});//?【問題出在這里】redisService.add2Set(cacheKey,?cityList);return?cityList;} }

    RedisService#add2Set 方法:

    public?class?RedisService?{//?...public?<T>?void?add2Set(String?key,?T...?values)?{redisTemplate.opsForSet().add(key,?values);} }

    乍一看好像沒什么問題。

    但是再一看,RedisService#add2Set 方法中,values 是可變長度類型的參數,如果把整個 cityList(java.util.Set 類型)作為一個參數傳給可變長度類型的參數會怎么樣呢?

    PS: 可變長度類型參數是 Java 中的一種語法糖,其實它本質上是一個數組。

    打個斷點看下:

    可以看到這里的 Set 類型,也就是傳入的 cityList 被當成了數組中的一個元素,怪不得會報錯。

    那這種情況該怎么處理呢?

    其實也很簡單,把 cityList 轉成數組就可以了:

    public?class?CityService?{public?Set<String>?findCityByCode(String?cityCode)?{//?...//?【問題出在這里】轉成數組,即?toArray?方法redisService.add2Set(cacheKey,?cityList.toArray());return?cityList;} }

    這樣入參就按照想要的方式來了:


    再觀察 Redis 的緩存值,可以看到也是想要的結果:


    到這里,問題算是搞定了。

    ?

    結語

    本文主要復盤了 Redis 使用過程中遇到的兩個問題:

  • Redis key/value 亂碼問題。原因是 RedisTemplate 的序列化問題,注意配置。

  • HashSet 和 String 類型轉換問題。主要是在操作 Redis 的 set 時(其他類型亦然),注意 API 的參數細節,不能想當然。

  • 漫漫踩坑路,且踩且珍惜。大家一起踩。

    有道無術,術可成;有術無道,止于術

    歡迎大家關注Java之道公眾號

    好文章,我在看??

    總結

    以上是生活随笔為你收集整理的Redis遇到的那些坑的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 欧美高跟鞋交xxxxxhd | 欧美va亚洲va| 91精品在线视频观看 | 在线播放一区二区三区 | 中文字幕+乱码+中文字幕明步 | 色综合国产 | 欧美大片xxxx | chinesepron hd videos国产91 | 日日夜夜天天干 | 黄色亚洲视频 | 免费在线看污视频 | 春色伊人 | 日本超碰 | 美女久久久久久久久 | jizz中国女人高潮 | 久久国产人妻一区二区免色戒电影 | 国产污视频 | 天天色综合久久 | 亚洲第5页| av毛片精品 | 亚洲成人久久久久 | 亚洲精品一区 | 国产精品乱码一区二区三区 | 色诱视频在线观看 | 成人77777| 亚洲在线免费观看视频 | 天天干天天日夜夜操 | 亚洲 激情 | 欧美成人91 | 在线欧美a | 美日韩中文字幕 | 午夜影院免费体验区 | 欧美 日韩 国产 成人 在线观看 | 欧美日一本 | 精品久久久久久久久久久久久久久久久 | 国产乱码精品一品二品 | 国产一区91| 国产精品嫩草av | 久久男女视频 | 在线人成 | 黄色网址进入 | 欧美寡妇性猛交 | 欧美与黑人午夜性猛交久久久 | 一级二级三级视频 | 大黑人交交护士xxxxhd | 麻豆传媒一区二区 | 久久色在线观看 | 成人黄色免费视频 | 涩涩视频网站在线观看 | 国产免费片| 日批视频免费 | 亚洲最新在线 | 黄色动漫在线免费观看 | 四虎图库 | 五月婷婷综合激情 | 91呦呦| 亚洲砖区区免费 | 97超碰精品 | 日韩欧洲亚洲 | 蜜臀av中文字幕 | 无码人妻丰满熟妇区五十路百度 | 国产一区二区高清视频 | 97插插插 | www.玖玖玖 | 青草视频在线免费观看 | 美女视频黄的免费 | 精品国产999久久久免费 | 欧美专区视频 | 成av在线 | 国产高清免费 | 国产69久久精品成人看 | 午夜国产一级 | 依人成人综合网 | 成 人 免费 黄 色 | 亚洲性夜 | 亚洲国产精品视频一区 | 苍井空亚洲精品aa片在线播放 | 2019国产精品视频 | 性少妇xxxxx 亚洲一卡二卡在线观看 | 精品国产99久久久久久宅男i | 天天摸天天舔天天操 | 成人免费视频一区二区 | 国产亚洲精品久久久久动 | 久久精彩 | 337p亚洲欧洲色噜噜噜 | 国产欧美日韩综合 | 91av在线免费 | 亚洲成人av电影在线 | 16一17女人毛片 | 原来神马电影免费高清完整版动漫 | 日产毛片 | 国产婷婷在线视频 | 国产精品精品国产 | 99久久免费看精品国产一区 | 波多野结衣二区三区 | 无码精品久久久久久久 | 久久精品大片 | 奇米综合网 | 中文字幕欧美另类精品亚洲 |