91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

incr自增怎么在spring-data-redis中實現

發布時間:2020-11-24 14:12:47 來源:億速云 閱讀:1458 作者:Leah 欄目:開發技術

這期內容當中小編將會給大家帶來有關incr自增怎么在spring-data-redis中實現,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

使用的RedisTemplate,做讀寫操作時候,都是要經過序列化和反序列化。

這時你使用redisTemplate.opsForValue().increment()就可能報錯redis.clients.jedis.exceptions.JedisDataException: ERR value is not an integer or out of range了。

valueOper.get(key) 獲取不到自增的值。

于是我去看了一下redis的官方文檔,找到一個解決方法

使用spring-data-redis實現incr自增
/**
   *
   * @param key
   * @param liveTime
   * @return
   */
  public Long incr(String key, long liveTime) {
    RedisAtomicLong entityIdCounter = new RedisAtomicLong(key, redisTemplate.getConnectionFactory());
    Long increment = entityIdCounter.getAndIncrement();

    if ((null == increment || increment.longValue() == 0) && liveTime > 0) {//初始設置過期時間
      entityIdCounter.expire(liveTime, TimeUnit.SECONDS);
    }

    return increment;
  }

這樣,上面的increment就是自增后的新知值,然后中間通過entityIdCounter.expire(liveTime, TimeUnit.SECONDS);設置過期時間。

當然這里比較討厭,spring沒有在創建RedisAtomicLong對象的時候一起設置過期時間。

可以看看其源碼,new RedisAtomicLong最終調用的是這個方法:

private RedisAtomicLong(String redisCounter, RedisConnectionFactory factory, Long initialValue) {
    Assert.hasText(redisCounter, "a valid counter name is required");
    Assert.notNull(factory, "a valid factory is required");

    RedisTemplate<String, Long> redisTemplate = new RedisTemplate<String, Long>();
    redisTemplate.setKeySerializer(new StringRedisSerializer());
    redisTemplate.setValueSerializer(new GenericToStringSerializer<Long>(Long.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);
    }
  }

可以看到,初始值是0。

然后根進set方法

public void set(long newValue) {
    operations.set(key, newValue);
  }

可以看到,他是采用的operations.set(key, newValue);但是明明還有一個重載的方法void set(K key, V value, long timeout, TimeUnit unit);可以設置過期時間,為啥spring不提供呢。

為了解決這個問題,我們可以自己模擬RedisAtomicLong方法,去實現一個帶有過期時間的自增方法。比較簡單,讀者自行擼代碼吧,這里就不寫出了。

補充知識:關于spring boot使用redis的increment()方法自增問題

需求是限制IP頻繁訪問某接口,用的方案是使用redis記錄訪問IP的值,先設定好初始值,每次訪問自增,達到某限定值后,進行阻止。

用的是自定義工具類,使用spring封裝的spring-data-redis進行操作,在對某key進行increment()方法時,報錯:

redis ERR value is not an integer or out of range

代碼邏輯如下:

Integer count = (Integer) redisUtil.get(ipAddress);//取得key的value
    if (count == null){
      redisUtil.set(ipAddress,1,10);
      return false;
    }else if(count == 3){
      return false;
    }else {
      redisUtil.incr(ipAddress,1);
      return false;
    }

第一次進來,如果沒有redis中沒有數據,則設置key,value和time,key是ip, value初始值為1,有效時長為10秒。

如果沒達到限制次數,則對key自增1。

redisUtil.incr()方法實現如下:

@Resource
  private RedisTemplate<String, Object> redisTemplate; //這里使用的是redisTemplate

  public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
    this.redisTemplate = redisTemplate;
  }

  /**
   * 遞增
   * @param key 鍵
//   * @param by 要增加幾(大于0)
   * @return
   */
  public long incr(String key, long delta){
    if(delta<0){
      throw new RuntimeException("遞增因子必須大于0");
    }
    return redisTemplate.opsForValue().increment(key, delta);
  }

開始以為是incr方法接受的參數是long型,但我傳入的是INTEGER類型,但轉換后還是沒有解決問題,問題不是出在這,后來通過查找資料發現,Spring對Redis序列化的策略有兩種,分別是StringRedisTemplate和RedisTemplate,其中StringRedisTemplate用于操作字符串,RedisTemplate使用的是JDK默認的二進制序列化。

大家都知道redis序列化是將key,value值先轉換為流的形式,再存儲到redis中。

RedisTemplate是使用的JdkSerializationRedisSerializer序列化,序列化后的值包含了對象信息,版本號,類信息等,是一串字符串,所以無法進行數值自增操作。

而StringRedisTemplate序列化策略是字符串的值直接轉為字節數組,所以存儲到redis中是數值,所以可以進行自增操作。

StringRedisSerializer源碼:

public class StringRedisSerializer implements RedisSerializer<String> {
  private final Charset charset;

  public StringRedisSerializer() {
    this(StandardCharsets.UTF_8);
  }

  public StringRedisSerializer(Charset charset) {
    Assert.notNull(charset, "Charset must not be null!");
    this.charset = charset;
  }

  public String deserialize(@Nullable byte[] bytes) {
    return bytes == null &#63; null : new String(bytes, this.charset);
  }

  public byte[] serialize(@Nullable String string) {
    return string == null &#63; null : string.getBytes(this.charset); //注意這里是字節數組
  }
}

所以問題出在這里,我們需要自定義序列化策略,在application啟動類中添加如下:

 @Bean
  public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
    StringRedisTemplate template = new StringRedisTemplate(factory);
    //定義key序列化方式
    //RedisSerializer<String> redisSerializer = new StringRedisSerializer();//Long類型會出現異常信息;需要我們上面的自定義key生成策略,一般沒必要
    //定義value的序列化方式
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);

    // template.setKeySerializer(redisSerializer);
    template.setValueSerializer(jackson2JsonRedisSerializer);
    template.setHashValueSerializer(jackson2JsonRedisSerializer);
    template.afterPropertiesSet();
    return template;

上述就是小編為大家分享的incr自增怎么在spring-data-redis中實現了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

岳阳市| 来宾市| 抚州市| 永善县| 隆德县| 阿克陶县| 余姚市| 桐城市| 突泉县| 盐津县| 乐清市| 朝阳县| 舟山市| 嘉黎县| 进贤县| 怀仁县| 南雄市| 新乡县| 长岭县| 淳安县| 大渡口区| 安义县| 黑水县| 册亨县| 焉耆| 阿合奇县| 微博| 清水河县| 阿拉善左旗| 正安县| 广元市| 黄石市| 湖州市| 寿阳县| 绥德县| 昌邑市| 德安县| 拜城县| 靖西县| 林口县| 六枝特区|