欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

最近工作中遇到了這樣一個(gè)場(chǎng)景

同一個(gè)外部單號(hào)生成了多張出庫(kù)單,等待所有相關(guān)的出庫(kù)單都出庫(kù)成功后回復(fù)成功消息外部系統(tǒng)調(diào)用方。因?yàn)槭欠植际讲枷到y(tǒng),我使用了RedisAtomicInteger計(jì)數(shù)器來(lái)判斷出庫(kù)單是否全部完成,數(shù)量達(dá)成時(shí)回復(fù)成功消息給外部系統(tǒng)調(diào)用方。

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

分析

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

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

原因

redis的increment是原子性,但new RedisAtomicInteger時(shí)會(huì)調(diào)用set方法來(lái)設(shè)置初始值,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è)務(wù)鎖或升級(jí)spring-data-redis版本。

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

那有沒有更簡(jiǎn)單方法呢,有。竟然是set方法導(dǎo)致的值覆蓋,那就不走set方法就可以了。

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

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

使用RedisAtomicInteger中間遇到的問題

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

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

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

參考redis命令說(shuō)明我們知道incr對(duì)操作值的要求

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

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

"\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命令對(duì)結(jié)果的要求是違背的。

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

會(huì)報(bào)java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String。

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

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

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

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

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

相關(guān)文章

  • Redisson實(shí)現(xiàn)分布式鎖、鎖續(xù)約的案例

    Redisson實(shí)現(xiàn)分布式鎖、鎖續(xù)約的案例

    這篇文章主要介紹了Redisson如何實(shí)現(xiàn)分布式鎖、鎖續(xù)約,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-03-03
  • 聊一聊Redis與MySQL雙寫一致性如何保證

    聊一聊Redis與MySQL雙寫一致性如何保證

    一致性就是數(shù)據(jù)保持一致,在分布式系統(tǒng)中,可以理解為多個(gè)節(jié)點(diǎn)中數(shù)據(jù)的值是一致的。本文給大家分享Redis與MySQL雙寫一致性該如何保證,感興趣的朋友一起看看吧
    2021-06-06
  • Redis整合Spring結(jié)合使用緩存實(shí)例

    Redis整合Spring結(jié)合使用緩存實(shí)例

    這篇文章主要介紹了Redis整合Spring結(jié)合使用緩存實(shí)例,介紹了如何在Spring中配置redis,并通過Spring中AOP的思想,將緩存的方法切入到有需要進(jìn)入緩存的類或方法前面。需要的朋友可以參考下
    2015-12-12
  • 阿里云官方Redis開發(fā)規(guī)范總結(jié)

    阿里云官方Redis開發(fā)規(guī)范總結(jié)

    本文主要介紹了阿里云官方Redis開發(fā)規(guī)范總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • 阿里云服務(wù)器安裝配置redis的方法并且加入到開機(jī)啟動(dòng)(推薦)

    阿里云服務(wù)器安裝配置redis的方法并且加入到開機(jī)啟動(dòng)(推薦)

    這篇文章主要介紹了阿里云服務(wù)器安裝配置redis并且加入到開機(jī)啟動(dòng),需要的朋友可以參考下
    2017-12-12
  • Redis與本地緩存的結(jié)合實(shí)現(xiàn)

    Redis與本地緩存的結(jié)合實(shí)現(xiàn)

    我們開發(fā)中經(jīng)常用到Redis作為緩存,本文主要介紹了Redis與本地緩存的結(jié)合實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Redisson分布式鎖之加解鎖詳解

    Redisson分布式鎖之加解鎖詳解

    這篇文章主要為大家介紹了Redisson分布式鎖加解鎖的詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • redis保存session信息的示例代碼

    redis保存session信息的示例代碼

    本文實(shí)現(xiàn)一個(gè)將session信息保存在 redis中,多個(gè)tomcat中的工程都從redis獲取session信息的示例,本文給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2023-01-01
  • redis+mysql+quartz 一種紅包發(fā)送功能的實(shí)現(xiàn)

    redis+mysql+quartz 一種紅包發(fā)送功能的實(shí)現(xiàn)

    這篇文章主要介紹了redis+mysql+quartz 一種紅包發(fā)送功能的實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • Redis連接超時(shí)異常的處理方法

    Redis連接超時(shí)異常的處理方法

    這篇文章主要給大家介紹了關(guān)于Redis連接超時(shí)異常的處理方法,文中通過示例代碼以及圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評(píng)論