redis缓存数据需要指定缓存有效时间范围段的多个解决方案 Calendar+quartz

在实现积分项目业务中,对不同场景设置了不同的key-value缓存到了redis中。但是因为对不同业务的key需要缓存的时间不尽相同,这里自定义工具类来实现。
设置redis缓存key,截取部分代码:

  try{
  //cacheManager就相当从redis链接池获取一个连接,具体工厂类获取在后面备注
  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){
    //累积积分;因为签到其实是没有每日积分的,是按次数规则累积的;但为了统一,直接用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这种希望指定缓存有效时间,现在提供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点毫秒数
     * @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点相差秒数
     * @return
     */
    public static Long getSecsToEndOfCurrentMonth(){

        Long secsOfNextMonth  = nextMonthFirstDate().getTime();
        //将当前时间转为毫秒数
        Long secsOfCurrentTime = new Date().getTime();
        //将时间转为秒数
        Long distance = (secsOfNextMonth - secsOfCurrentTime)/1000;
        if (distance > 0 && distance != null){
            return distance;
        }

        return new Long(0);

    }



    /**
     * 获取当前时间到明天凌晨0点相差秒数
     * @return
     */
    public static Long getSecsToEndOfCurrentDay() throws ParseException {

        Long secsOfNextDay  = nextDayFirstDate().getTime();
        //将当前时间转为毫秒数
        Long secsOfCurrentTime = new Date().getTime();
        //将时间转为秒数
        Long distance = (secsOfNextDay - secsOfCurrentTime)/1000;
        if (distance > 0 && distance != null){
            return distance;
        }

        return new Long(0);

    }
}

3、使用定时任务定时清空redis缓存;避免出现定时任务异常,我的业务代码里都保障了两种方案都适用。
定时任务保证,到指定时间直接调用代码进行操作;代码里直接调用shell脚本直接删掉相关redis的缓存数据。
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" /><!-- 定时执行 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 点执行 -->
        <!--<property name="cronExpression" value="0 */1 * * * ?" />&lt;!&ndash; 每隔1min执行一次 &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>
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值