定时任务/线程排队

该博客介绍了一个使用Spring的@Scheduled注解实现的定时任务,该任务每天0点执行,从Redis中读取PV和UV数据,实例化到Fwltj对象并保存到数据库,同时清除Redis中的对应数据。任务利用RedisTemplate进行操作,通过scan方法批量查找key,并通过多线程处理数据,确保高效执行。
摘要由CSDN通过智能技术生成
/**
 * 定时任务类
 * 每天0点取出数据实例化道数据库中
 */
@Component
public class MyJob {
    @Resource
    private RedisTemplate redisTemplate;

    private RedisTemplate<String, Integer> intRedisTemplate;

    @Resource
    private FwltjService fwltjService;

    private Logger logger = LoggerFactory.getLogger(MyJob.class);

    //PV,UV头缀
    String pVKeyPrefix = WebConstant.PV_KEY_PREFIX;
    String uVKeyPrefix = WebConstant.UV_KEY_PREFIX;

    /**
     * cron表达式
     * 每天 17:30:00 执行一次定时任务
     * @Scheduled(cron = "0 30 17 * * ?")
     * 每天 00:00:00执行一次定时任务
     */
    @Scheduled(cron = "0 0 0 * * ? ")
    public void cron() {
        logger.info(new Date() + " 进入定时任务");
        deleteKeyAndSaveDatabase();
        logger.info(new Date() + " 定时任务结束");
    }

    /**
     * 实例化到数据库中
     */
    public void deleteKeyAndSaveDatabase() {
        Fwltj fwltj = new Fwltj();
        logger.info(new Date() + " 实例化Redis缓存");
        RedisTemplate<String, Integer> intRedis = getIntRedisTemplate();

        //查询以此开头所有的key,工具替换keys
        Set<String> keysPv = scan(intRedis, pVKeyPrefix);
        Set<String> keysUv = scan(intRedis, uVKeyPrefix);

        //遍历所有的key,线程排队
        Vector<Thread> threadVector = new Vector<>();
        Thread childThread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (String pvRedisKey : keysPv) {

                    String visitIp = pvRedisKey.split("_")[1];
                    int pVNum = intRedis.opsForValue().get(pvRedisKey);

                    //uvKey为头缀+IP
                    String uvRedisKey = WebConstant.UV_KEY + visitIp;
                    Boolean pvKeyBoolean = intRedis.hasKey(uvRedisKey);
                    if (pvKeyBoolean) {
                        int uVNum = intRedis.opsForValue().get(uvRedisKey);
                        //将key,value实例化到数据库中
                        //访问时间,IP,PV,UV
                        fwltj.setTjrq(new Date());
                        fwltj.setIp(visitIp);
                        fwltj.setPv(pVNum + "");
                        fwltj.setUv(uVNum + "");
                        fwltjService.addF(fwltj);
                        logger.info("visitIp: " + visitIp + " , pVNum: " + pVNum + " , uVNum: " + uVNum);
                    }
                }
            }
        });
        threadVector.add(childThread);
        childThread.start();

        //线程排序
        for (Thread thread : threadVector) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //0点清除redis
        if (!keysPv.isEmpty() & !keysUv.isEmpty()) {
            //删除redis中所对应的值
            redisTemplate.delete(keysPv);
            redisTemplate.delete(keysUv);
            logger.info(new Date() + " 清除Redis缓存");
        }
    }

    /**
     * scan 实现批量查找key
     *
     * @param redisTemplate redisTemplate
     * @param pattern       表达式,如:abc*,找出所有以abc开始的键
     */
    public Set<String> scan(RedisTemplate<String, Integer> redisTemplate, String pattern) {
        return redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
            Set<String> keysTmp = new HashSet<>();
            try (Cursor<byte[]> cursor = connection.scan(new ScanOptions.ScanOptionsBuilder()
                    .match(pattern)
                    .count(10000).build())) {

                while (cursor.hasNext()) {
                    keysTmp.add(new String(cursor.next(), "Utf-8"));
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            return keysTmp;
        });
    }

    /**
     * redis实例化
     *
     * @return
     */
    private RedisTemplate<String, Integer> getIntRedisTemplate() {
        if (intRedisTemplate == null) {
            intRedisTemplate = initTemplate();
        }
        return intRedisTemplate;
    }

    private RedisTemplate<String, Integer> initTemplate() {
        RedisTemplate<String, Integer> template = new RedisTemplate<String, Integer>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericToStringSerializer<Integer>(Integer.class));
        template.setExposeConnection(true);
        template.setConnectionFactory(redisTemplate.getConnectionFactory());
        template.afterPropertiesSet();
        return template;
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值