最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用RedisAtomicInteger計數(shù)出現(xiàn)少計問題及解決

 更新時間:2022年11月22日 15:04:20   作者:碼農(nóng)_ckg  
這篇文章主要介紹了使用RedisAtomicInteger計數(shù)出現(xiàn)少計問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

RedisAtomicInteger計數(shù)出現(xiàn)少計

最近工作中遇到了這樣一個場景

同一個外部單號生成了多張出庫單,等待所有相關的出庫單都出庫成功后回復成功消息外部系統(tǒng)調(diào)用方。因為是分布式布系統(tǒng),我使用了RedisAtomicInteger計數(shù)器來判斷出庫單是否全部完成,數(shù)量達成時回復成功消息給外部系統(tǒng)調(diào)用方。

在本地測試和測試環(huán)境測試時都沒有發(fā)現(xiàn)問題,到了生產(chǎn)環(huán)境后,發(fā)現(xiàn)偶爾出現(xiàn)所有出庫單都已經(jīng)出庫,但沒有回復消息給調(diào)用方,如:出庫單15張,但計數(shù)器只有14。

分析

開始以為是有單據(jù)漏計算了,通過日志分析,發(fā)現(xiàn)所有的出庫單都統(tǒng)計進去了。

然后通過增加打開調(diào)試日志,發(fā)現(xiàn)最開始的2張出庫單統(tǒng)計后的值都為1,少了1個。

原因

redis的increment是原子性,但new RedisAtomicInteger時會調(diào)用set方法來設置初始值,set方法是可以被后面的方法覆蓋的。

edisAtomicInteger redisAtomicInt = new RedisAtomicInteger(countKey, redisTemplate.getConnectionFactory());
??
// spring-data-redis-1.8.13原碼
public RedisAtomicInteger(String redisCounter, RedisConnectionFactory factory) {
?? ??? ?this(redisCounter, factory, null);
?? ?}
??
private RedisAtomicInteger(String redisCounter, RedisConnectionFactory factory, Integer initialValue) {
?? ??? ?RedisTemplate<String, Integer> redisTemplate = new RedisTemplate<String, Integer>();
?? ??? ?redisTemplate.setKeySerializer(new StringRedisSerializer());
?? ??? ?redisTemplate.setValueSerializer(new GenericToStringSerializer<Integer>(Integer.class));
?? ??? ?redisTemplate.setExposeConnection(true);
?? ??? ?redisTemplate.setConnectionFactory(factory);
?? ??? ?redisTemplate.afterPropertiesSet();
?
?? ??? ?this.key = redisCounter;
?? ??? ?this.generalOps = redisTemplate;
?? ??? ?this.operations = generalOps.opsForValue();
?
?? ??? ?if (initialValue == null) {
?? ??? ??? ?if (this.operations.get(redisCounter) == null) {
?? ??? ??? ??? ?set(0);
?? ??? ??? ?}
?? ??? ?} else {
?? ??? ??? ?set(initialValue);
?? ??? ?}
?? ?}

解決方法

網(wǎng)上看到的都是加業(yè)務鎖或升級spring-data-redis版本。

但老項目升級spring-data-redis版本可能會引起兼容性問題,加業(yè)務鎖又增加了代碼復雜度。

那有沒有更簡單方法呢,有。竟然是set方法導致的值覆蓋,那就不走set方法就可以了。

增加下面一行代碼解決問題

// Fixed bug 前幾個數(shù)累計重復問題
redisTemplate.opsForValue().setIfAbsent(countKey, 0);

使用RedisAtomicInteger中間遇到的問題

RedisAtomicInteger是springdata中在redis的基礎上實現(xiàn)的原子計數(shù)器,在以下maven依賴包中:

<groupId>org.springframework.data</groupId> ? ??
<artifactId>spring-data-redis</artifactId>?

當使用RedisAtomicInteger(String redisCounter, RedisOperations<String, Integer> template,...)函數(shù)構建實例的情況下,在使用INCR或者DECR時,會遇到ERR value is not an integer or out of range錯誤,顯示操作的數(shù)據(jù)不是一個整數(shù)或者超出范圍。

參考redis命令說明我們知道incr對操作值的要求

這是一個針對字符串的操作,因為 Redis 沒有專用的整數(shù)類型,所以 key 內(nèi)儲存的字符串被解釋為十進制 64 位有符號整數(shù)來執(zhí)行 INCR 操作。如果值包含錯誤的類型,或字符串類型的值不能表示為數(shù)字,那么返回一個錯誤。

從redis實例中查看該key的value,會發(fā)現(xiàn)結果類似這樣:

"\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.Number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x00\x01"

原因在于value使用的序列化方式是JdkSerializationRedisSerializer,這和INCR命令對結果的要求是違背的。

該使用哪種序列化方式把value放進去呢?按照INCR命令對結果的要求,最容易想到StringRedisSerializer,但經(jīng)過嘗試這也行不通

會報java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String。

如果看過RedisAtomicInteger的源碼,在private RedisAtomicInteger(String redisCounter, RedisConnectionFactory factory, Integer initialValue)中會發(fā)現(xiàn)方法內(nèi)部創(chuàng)建了RedisTemplate實例,對value設置的序列化方式是GenericToStringSerializer。

該序列化內(nèi)部使用spring core包下的
org.springframework.core.convert.support.DefaultConversionService作為默認的對象和字符串的轉換方式,主要為了滿足大多數(shù)環(huán)境的要求。

至此,我們終于知道了錯誤的根本原因,構造RedisAtomicInteger時傳入的redisTemplate是有問題的,value的默認序列化方式不滿足RedisAtomicInteger的需要。那么問題也迎刃而解,將GenericToStringSerializer作為redisTemplate的value序列化方式。

這樣雖然解決了問題,但很麻煩,很可能為了RedisAtomicInteger的要求需要再創(chuàng)建一個redisTemplate,簡直不能忍受。再看RedisAtomicInteger的源碼,發(fā)現(xiàn)構造函數(shù)除了可以用redisTemplate,還可以用RedisConnectionFactory,嘗試之后,完美解決。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • 詳解Redis中地理位置功能Geospatial的應用

    詳解Redis中地理位置功能Geospatial的應用

    Geospatial?Indexes?是?Redis?提供的一種數(shù)據(jù)結構,用于存儲和查詢地理位置信息,這篇文章就來和大家詳細講講Geospatial的具體應用吧
    2023-06-06
  • 記錄一次并發(fā)情況下的redis導致服務假死的問題解決

    記錄一次并發(fā)情況下的redis導致服務假死的問題解決

    由于Redis需要依賴于操作系統(tǒng)環(huán)境,如果系統(tǒng)資源受限,比如過量的進程在擠占系統(tǒng)資源、系統(tǒng)死鎖等情況,本文主要介紹了記錄一次并發(fā)情況下的redis導致服務假死的問題解決,感興趣的可以了解一下
    2023-09-09
  • windows下使用redis requirepass認證不起作用的解決方法

    windows下使用redis requirepass認證不起作用的解決方法

    今天小編就為大家分享一篇windows下使用redis requirepass認證不起作用的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-05-05
  • redis專屬鏈表ziplist的使用

    redis專屬鏈表ziplist的使用

    本文主要介紹了redis專屬鏈表ziplist的使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 基于Redis位圖實現(xiàn)系統(tǒng)用戶登錄統(tǒng)計

    基于Redis位圖實現(xiàn)系統(tǒng)用戶登錄統(tǒng)計

    這篇文章主要介紹了基于Redis位圖實現(xiàn)系統(tǒng)用戶登錄統(tǒng)計,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • Redis教程(十五):C語言連接操作代碼實例

    Redis教程(十五):C語言連接操作代碼實例

    這篇文章主要介紹了Redis教程(十五):C語言連接操作代碼實例,本篇博客是該系列博客中的最后一篇,在這里將給出基于Redis客戶端組件訪問并操作Redis服務器的代碼示例,需要的朋友可以參考下
    2015-05-05
  • Redis?搭建主從集群的操作指南

    Redis?搭建主從集群的操作指南

    單節(jié)點的?Redis?并發(fā)能力有限,要進一步提高?Redis?的并發(fā)能力,就需要搭建主從集群,實現(xiàn)讀寫分離,這篇文章主要給大家介紹了Redis搭建主從集群的操作指南,需要的朋友可以參考下
    2023-08-08
  • Redis設置database不生效的解決方案

    Redis設置database不生效的解決方案

    最近在做redis緩存設置的時候,發(fā)現(xiàn)即使已經(jīng)設置了database, 但是存數(shù)據(jù)的時候還是用的默認0數(shù)據(jù)庫,所以本文就給大家介紹了Redis設置database不生效的解決方案,需要的朋友可以參考下
    2023-08-08
  • Redis慢查詢的具體使用

    Redis慢查詢的具體使用

    慢查詢顧名思義就是比較慢的查詢,但是究竟是哪里慢呢?本文詳細的介紹了Redis慢查詢的具體使用,具有一定的參考價值,感興趣的可以了解一下
    2023-06-06
  • Redis的持久化方式

    Redis的持久化方式

    Redis提供了兩種主要的持久化方式:RDB和AOF,RDB通過定時快照的方式保存數(shù)據(jù)狀態(tài),而AOF記錄每個寫操作以便于重啟時重放,兩者可以結合使用,且在重啟時AOF文件會被優(yōu)先用于數(shù)據(jù)恢復,RDB快照具有速度快、節(jié)省磁盤空間的優(yōu)點,但可能會丟失最近的數(shù)據(jù)
    2024-10-10

最新評論

萨嘎县| 平阳县| 都兰县| 丹阳市| 康保县| 肥乡县| 松江区| 建昌县| 额济纳旗| 马公市| 安阳市| 衡东县| 嘉禾县| 柘荣县| 吴桥县| 柞水县| 安仁县| 江都市| 满城县| 凤凰县| 吉安市| 于田县| 高安市| 乌鲁木齐县| 富顺县| 洮南市| 揭西县| 赤城县| 太和县| 富源县| 徐汇区| 阳东县| 潼关县| 凌海市| 新宁县| 观塘区| 新民市| 上饶市| 修武县| 牟定县| 邢台县|