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

Redis有效時間設置以及時間過期處理操作

 更新時間:2020年11月24日 16:46:00   作者:月未明  
這篇文章主要介紹了Redis有效時間設置以及時間過期處理操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

本文對redis的過期處理機制做個簡單的概述,讓大家有個基本的認識。

Redis中有個設置時間過期的功能,即對存儲在redis數(shù)據(jù)庫中的值可以設置一個過期時間。作為一個緩存數(shù)據(jù)庫,這是非常實用的。如我們一般項目中的token或者一些登錄信息,尤其是短信驗證碼都是有時間限制的,按照傳統(tǒng)的數(shù)據(jù)庫處理方式,一般都是自己判斷過期,這樣無疑會嚴重影響項目性能。

一、有效時間設置:

redis對存儲值的過期處理實際上是針對該值的鍵(key)處理的,即時間的設置也是設置key的有效時間。Expires字典保存了所有鍵的過期時間,Expires也被稱為過期字段。

四種處理策略

EXPIRE 將key的生存時間設置為ttl秒

PEXPIRE 將key的生成時間設置為ttl毫秒

EXPIREAT 將key的過期時間設置為timestamp所代表的的秒數(shù)的時間戳

PEXPIREAT 將key的過期時間設置為timestamp所代表的的毫秒數(shù)的時間戳

其實以上幾種處理方式都是根據(jù)PEXPIREAT來實現(xiàn)的,設置生存時間的時候是redis內部計算好時間之后在內存處理的,最終的處理都會轉向PEXPIREAT。

1、2兩種方式是設置一個過期的時間段,就是咱們處理驗證碼最常用的策略,設置三分鐘或五分鐘后失效,把分鐘數(shù)轉換成秒或毫秒存儲到redis中。

3、4兩種方式是指定一個過期的時間 ,比如優(yōu)惠券的過期時間是某年某月某日,只是單位不一樣。

二、過期處理

過期鍵的處理就是把過期鍵刪除,這里的操作主要是針對過期字段處理的。

Redis中有三種處理策略:定時刪除、惰性刪除和定期刪除。

定時刪除:在設置鍵的過期時間的時候創(chuàng)建一個定時器,當過期時間到的時候立馬執(zhí)行刪除操作。不過這種處理方式是即時的,不管這個時間內有多少過期鍵,不管服務器現(xiàn)在的運行狀況,都會立馬執(zhí)行,所以對CPU不是很友好。

惰性刪除:惰性刪除策略不會在鍵過期的時候立馬刪除,而是當外部指令獲取這個鍵的時候才會主動刪除。處理過程為:接收get執(zhí)行、判斷是否過期(這里按過期判斷)、執(zhí)行刪除操作、返回nil(空)。

定期刪除:定期刪除是設置一個時間間隔,每個時間段都會檢測是否有過期鍵,如果有執(zhí)行刪除操作。這個概念應該很好理解。

看完上面三種策略后可以得出以下結論:

4. 1、3為主動刪除,2為被動刪除。

5. 1是實時執(zhí)行的,對CPU不是很友好,但是這在最大程度上釋放了內存,所以這種方式算是一種內存優(yōu)先優(yōu)化策略。

6. 2、3為被動刪除,所以過期鍵應該會存在一定的時間,這樣就使得過期鍵不會被立馬刪除,仍然占用著內存。但是惰性刪除的時候一般是單個刪除,相對來說對CPU是友好的。

7. 定期鍵這種刪除策略是一種讓人很蛋疼的策略,它既有避免1、2兩種策略劣勢的可能,也有同時發(fā)生1、2兩種策略劣勢的可能。如果定期刪除執(zhí)行的過于頻繁就可能會演變成定時刪除,如果執(zhí)行的過少就有可能造成過多過期鍵未被刪除而占用過多內存,如果時間的設置不是太好,既可能占用過多內存又同時對CPU產生不好的影響。所以。使用定期刪除的時候一定要把握好這個刪除的時間點。存在即為合理,既然開發(fā)的時候有這種策略,就說明定期刪除還是有他的優(yōu)勢的,具體大家可以自己琢磨。

三、主從服務器刪除過期鍵處理

參考書上說的有三種:RDB持久化、AOF持久化和復制功能。

RDB:

1. 主服務器模式運行在載入RDB文件時,程序會檢查文件中的鍵,只會加載未過期的,過期的會被忽略,所以RDB模式下過期鍵不會對主服務器產生影響。

2. 從服務器運行載入RDB文件時,會載入所有鍵,包括過期和未過期。當主服務器進行數(shù)據(jù)同步的時候,從服務器的數(shù)據(jù)會被清空,所以RDB文件的過期鍵一般不會對從服務器產生影響。

AOF:

AOF文件不會受過期鍵的影響。如果有過期鍵未被刪除,會執(zhí)行以下動作:

客戶端請求時(過期鍵):

1.從數(shù)據(jù)庫充刪除被訪問的過期鍵;

2.追加一條DEL 命令到AOF文件;

3.向執(zhí)行請求的客戶端回復nil(空)。

復制:

1.主服務器刪除過期鍵之后,向從服務器發(fā)送一條DEL指令,告知刪除該過期鍵。

2.從服務器接收到get指令的時候不會對過期鍵進行處理,只會當做未過期鍵一樣返回。(為了保持主從服務器數(shù)據(jù)的一致性)

3.從服務器只有接到主服務器發(fā)送的DEL指令后才會刪除過期鍵。

參考書籍:《Redis設計與實現(xiàn)》黃健宏著

補充知識:redis緩存數(shù)據(jù)需要指定緩存有效時間范圍段的多個解決方案 Calendar+quartz

在實現(xiàn)積分項目業(yè)務中,對不同場景設置了不同的key-value緩存到了redis中。但是因為對不同業(yè)務的key需要緩存的時間不盡相同,這里自定義工具類來實現(xiàn)。

設置redis緩存key,截取部分代碼:

try{
 //cacheManager就相當從redis鏈接池獲取一個連接,具體工廠類獲取在后面?zhèn)渥?
 cacheManager = (RedisCacheManager) CacheManagerFactory.getCacheManager();
 totalMonCount = Float.parseFloat(cacheManager.getString(monthKey)) + centCount;
 if (centLimitByMonth != -1){
   if (totalMonCount > centLimitByMonth) {
      // 超出月上限不再累計
      logger.error("exceeds the month limit cents! [" + totalMonCount + "]  code:[" + code + "]");
      return null;
   }
}

//當未超出月額度,此時要對日額度進行判斷;只需判斷其是否超出日上限積分
if (dayKey != null){
  //累積積分;因為簽到其實是沒有每日積分的,是按次數(shù)規(guī)則累積的;但為了統(tǒng)一,直接用centCount代替(都是簽一次1分)
  totalDayCount = Float.parseFloat(cacheManager.getString(dayKey)) + centCount;
  if (centLimitByDay != -1){
     if (totalDayCount > centLimitByDay){
      logger.info("[ERROR]teacher everyday assign cents > month limit! total: ["+totalDayCount+"]");
      return null;
     }
   }
   cacheManager.set(dayKey,totalDayCount.toString(),DateUtil.getSecsToEndOfCurrentDay());

}
//對月限制key進行積分累加
//每月1號凌晨1點啟動腳本刪除,同時設置了保存到月底緩存時間雙重保障
cacheManager.set(monthKey, totalMonCount.toString(), DateUtil.getSecsToEndOfCurrentDay());
logger.info("==monthkey:"+monthKey+"---value:"+totalMonCount);
 }
              ...
}catch(Exception e){
          logger.error("===cache redis fail!");
          e.printStackTrace();

      }finally {

          if (cacheManager != null){
              cacheManager.close();
          }
      }

//工廠類獲取redis鏈接
public class CacheManagerFactory {
  private static ICacheManager cacheManager;
  private CacheManagerFactory(){
  };

  public static ICacheManager getCacheManager(){
    if(cacheManager == null){
      synchronized (CacheManagerFactory.class) {
        if(cacheManager == null){
          JedisPooler jedisPooler = RedisPoolerFactory.getJedisPooler();
          cacheManager = new RedisCacheManager(jedisPooler);
        }
      }
    }
    return cacheManager;
 }
}

//redis鏈接池工廠類獲取鏈接
public class RedisPoolerFactory {
  private static JedisPooler jedisPooler; 
  private RedisPoolerFactory(){
  };

  public static JedisPooler getJedisPooler(){
    if(jedisPooler == null){
      synchronized (RedisPoolerFactory.class) {
        if(jedisPooler == null){
          jedisPooler = new JedisPooler();
        }
      }
    }
    return jedisPooler;
 }
}


/**
 * 
 * Redis 連接池實例
 * 
 * @author Ethan.Lam
 * @createTime 2011-12-3
 * 
 */
public class JedisPooler {

  private JedisPool pool;
  private String REDIS_HOST;
  private String REDIS_PSW;
  private int REDIS_PORT;
  private int REDIS_MaxActive;
  private int REDIS_MaxIdle;
  private int REDIS_MaxWait;

  public JedisPooler(String config) {
    __init(config);
  }

  public JedisPooler() {
    __init("/jedisPool.properties");
  }

  private void __init(String conf) {
    // 完成初始化工作
    Properties prop = new Properties();
    try {
      InputStream _file = loadConfig(conf);
      prop.load(_file);
      REDIS_HOST = prop.getProperty("REDIS.HOST");
      REDIS_PSW = prop.getProperty("REDIS.PSW");
      REDIS_PORT = Integer.parseInt(prop.getProperty("REDIS.PORT").trim());
      REDIS_MaxActive = Integer.parseInt(prop.getProperty("REDIS.MaxActive").trim());
      REDIS_MaxIdle = Integer.parseInt(prop.getProperty("REDIS.MaxIdle").trim());
      REDIS_MaxWait = Integer.parseInt(prop.getProperty("REDIS.MaxWait").trim());
    } catch (Exception e) {
      e.printStackTrace();
      REDIS_HOST = "localhost";
      throw new NullPointerException(conf + " is not found !");
    }
    JedisPoolConfig config = new JedisPoolConfig();
    config.setMaxActive(REDIS_MaxActive);
    config.setMaxIdle(REDIS_MaxIdle);
    config.setMaxWait(REDIS_MaxWait);
    config.setTestOnBorrow(true);
    System.out.println("REDIS Cache服務信息: 當前連接的服務IP為:" + REDIS_HOST + ":" + REDIS_PORT);
    if (null == REDIS_PSW || "".equals(REDIS_PSW.trim())){
      pool = new JedisPool(config, REDIS_HOST, REDIS_PORT, 5000);
    }
    else{
      pool = new JedisPool(config, REDIS_HOST, REDIS_PORT, 5000, REDIS_PSW);
    }
  }

  public Jedis getJedis() {
    return pool.getResource();
  }

  public void returnResource(Jedis jedis) {
    pool.returnResource(jedis);
  }

  public JedisPool getPool() {
    return pool;
  }

  InputStream loadConfig(String configPath) throws Exception {
    InputStream _file = null;
    try {
      String file = JedisPooler.class.getResource(configPath).getFile();
      file = URLDecoder.decode(file);
      _file = new FileInputStream(file);
    } catch (Exception e) {
      System.out.println("讀取jar中的配置文件....");
      String currentJarPath = URLDecoder.decode(JedisPooler.class.getProtectionDomain()
          .getCodeSource().getLocation().getFile(), "UTF-8"); // 獲取當前Jar文件名
      System.out.println("currentJarPath:" + currentJarPath);
      java.util.jar.JarFile currentJar = new java.util.jar.JarFile(currentJarPath);
      java.util.jar.JarEntry dbEntry = currentJar.getJarEntry("jedisPool.properties");
      InputStream in = currentJar.getInputStream(dbEntry);
      _file = in;
    }
    return _file;
  }
}

可以看到,這里cacheManager.set(monthKey, totalMonCount.toString(), DateUtil.getSecsToEndOfCurrentDay()); 就用到了工具類獲取了指定的時間范圍。

對于redis這種希望指定緩存有效時間,現(xiàn)在提供3種方案:

1、自定義確切時間:

public static final long LoginCentTimeByDay = 86400;//s 未認證失效時間 1天

public static final long LoginCentTimeByMonth = 86400*30; //s 時效時間 30天

直接指定:

cacheManager.set(monthKey, totalMonCount.toString(),LoginCentTimeByDay)

2、自定義工具類,獲取當前時間到第二天的零點、下個月1號零點的時間差(s):

cacheManager.set(monthKey, totalMonCount.toString(), DateUtil.getSecsToEndOfCurrentDay());
public class DateUtil {
  /**
   *獲取每月最后一天時間
   * @param sDate1
   * @return
   */
  public static Date getLastDayOfMonth(Date sDate1)  {
    Calendar cDay1 = Calendar.getInstance();
    cDay1.setTime(sDate1);
    final int lastDay = cDay1.getActualMaximum(Calendar.DAY_OF_MONTH);
    Date lastDate = cDay1.getTime();
    lastDate.setDate(lastDay);
    return lastDate;
  }

  /*
  獲取下一個月第一天凌晨1點
   */
  public static Date nextMonthFirstDate() {
    Calendar calendar = Calendar.getInstance();
    calendar.set(Calendar.HOUR_OF_DAY, 1);  //設置為每月凌晨1點
    calendar.set(Calendar.DAY_OF_MONTH, 1);  //設置為每月1號
    calendar.add(Calendar.MONTH, 1);  // 月份加一,得到下個月的一號
//    calendar.add(Calendar.DATE, -1);   下一個月減一為本月最后一天
    return calendar.getTime();
  }

  /**
   * 獲取第二天凌晨0點毫秒數(shù)
   * @return
   */
  public static Date nextDayFirstDate() throws ParseException {
    Calendar cal = Calendar.getInstance();
    cal.setTime(new Date());
    cal.add(Calendar.DAY_OF_YEAR, 1);
    cal.set(Calendar.HOUR_OF_DAY, 00);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    return cal.getTime();
  }

  //*********

  /**
   * 獲取當前時間到下個月凌晨1點相差秒數(shù)
   * @return
   */
  public static Long getSecsToEndOfCurrentMonth(){

    Long secsOfNextMonth = nextMonthFirstDate().getTime();
    //將當前時間轉為毫秒數(shù)
    Long secsOfCurrentTime = new Date().getTime();
    //將時間轉為秒數(shù)
    Long distance = (secsOfNextMonth - secsOfCurrentTime)/1000;
    if (distance > 0 && distance != null){
      return distance;
    }
    return new Long(0);
  }

  /**
   * 獲取當前時間到明天凌晨0點相差秒數(shù)
   * @return
   */
  public static Long getSecsToEndOfCurrentDay() throws ParseException {

    Long secsOfNextDay = nextDayFirstDate().getTime();
    //將當前時間轉為毫秒數(shù)
    Long secsOfCurrentTime = new Date().getTime();
    //將時間轉為秒數(shù)
    Long distance = (secsOfNextDay - secsOfCurrentTime)/1000;
    if (distance > 0 && distance != null){
      return distance;
    }
    return new Long(0);
  }
}

3、使用定時任務定時清空redis緩存;避免出現(xiàn)定時任務異常,我的業(yè)務代碼里都保障了兩種方案都適用。

定時任務保證,到指定時間直接調用代碼進行操作;代碼里直接調用shell腳本直接刪掉相關redis的緩存數(shù)據(jù)。

quartz定時任務就需要注意定義相應的cron時間:

我的定時任務的配置文件quartz.xml中定義:

  <!--定時任務1-->
  <!-- 每天12點將當天用戶積分行為緩存清掉 -->
  <bean id="deleteRedisCacheDayUsersJob" class="cn.qtone.xxt.cent.quartz.delRedisCacheCentUsers" />
  <bean id="deleteRedisCacheDayUsersTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="deleteRedisCacheDayUsersJob" />
    <property name="targetMethod" value="delCurrentDayCacheUsersByDay" /><!-- 定時執(zhí)行 doItem 方法 -->
    <property name="concurrent" value="false" />
  </bean>
  <bean id="deleteRedisCacheDayUsersTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
    <property name="jobDetail" ref="deleteRedisCacheDayUsersTask" />
    <property name="cronExpression" value="59 59 23 * * ?" /><!-- 每天凌晨23:59:59 點執(zhí)行 -->
    <!--<property name="cronExpression" value="0 */1 * * * ?" />&lt;!&ndash; 每隔1min執(zhí)行一次 &ndash;&gt;-->
  </bean>
  <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
      <list>
         <ref bean="deleteRedisCacheDayUsersTrigger" />
        <ref bean="deleteRedisCacheMonthUsersTrigger" />
        <!--暫時不用-->
         <!--<ref bean="centUpdateByMonthTrigger" />-->
      </list>
    </property>
  </bean>

以上這篇Redis有效時間設置以及時間過期處理操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • 實時計算知多少?

    實時計算知多少?

    這篇文章對滑動窗口計數(shù)的概念和關鍵代碼做了較為詳細解釋,讓我們對實時計算這一概念有了更深的了解,需要的朋友可以參考下
    2015-07-07
  • springboot使用@value注入配置失敗的解決

    springboot使用@value注入配置失敗的解決

    這篇文章主要介紹了springboot使用@value注入配置失敗的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringBoot整合Activiti工作流框架的使用

    SpringBoot整合Activiti工作流框架的使用

    本文主要介紹了SpringBoot整合Activiti工作流框架的使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 新手小白學JAVA IDEA下載使用手冊全集

    新手小白學JAVA IDEA下載使用手冊全集

    IDEA的每一個方面都是為了最大限度地提高開發(fā)人員的工作效率而設計的,它的智能編碼輔助和人機工程學設計會讓開發(fā)過程變得愉悅且高效,今天給大家分享新手小白學JAVA IDEA下載使用手冊全集,對idea新手使用相關知識感興趣的朋友跟隨小編一起學習吧
    2021-05-05
  • Java多線程編程中使用Condition類操作鎖的方法詳解

    Java多線程編程中使用Condition類操作鎖的方法詳解

    Condition是java.util.concurrent.locks包下的類,提供了對線程鎖的更精細的控制方法,下面我們就來看一下Java多線程編程中使用Condition類操作鎖的方法詳解
    2016-07-07
  • 詳解MyBatis resultType與resultMap中的幾種返回類型

    詳解MyBatis resultType與resultMap中的幾種返回類型

    本文主要介紹了MyBatis resultType與resultMap中的幾種返回類型,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Java實戰(zhàn)之吃貨聯(lián)盟訂餐系統(tǒng)

    Java實戰(zhàn)之吃貨聯(lián)盟訂餐系統(tǒng)

    這篇文章主要介紹了Java實戰(zhàn)之吃貨聯(lián)盟訂餐系統(tǒng),文中有非常詳細的代碼示例,對正在學習java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • 淺談SpringBoot 中關于自定義異常處理的套路

    淺談SpringBoot 中關于自定義異常處理的套路

    這篇文章主要介紹了淺談SpringBoot 中關于自定義異常處理的套路,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • plantuml畫圖實現(xiàn)代碼畫時序圖UML用例圖

    plantuml畫圖實現(xiàn)代碼畫時序圖UML用例圖

    這篇文章主要為大家介紹了plantuml畫圖實現(xiàn)代碼畫時序圖示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • Java面試之動態(tài)規(guī)劃與組合數(shù)

    Java面試之動態(tài)規(guī)劃與組合數(shù)

    這篇文章主要介紹了Java面試之動態(tài)規(guī)劃與組合數(shù)的相關知識,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09

最新評論