定时任务

定时任务

在实际项目开发中,除了Web应用、SOA服务外,还有一类不可缺少的,那就是定时任务调度。定时任务的场景可以说非常广泛:

  • 某些网站会定时发送优惠邮件;

  • 银行系统还款日信用卡催收款;

  • 某些应用的生日祝福短信等。

那究竟何为定时任务调度,一句话概括就是:基于给定的时间点、给定的时间间隔、自动执行的任务

 

 

2.3.1 入门案例

admin

  • 修改模块引导类,开启SpringTask功能支持

@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
@MapperScan("com.tanhua.admin.mapper")
@EnableScheduling //开启定时任务支持
public class AdminServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(AdminServerApplication.class,args);
    }
}

配置定时任务类

@Component
public class AnalysisTask {
    
    /**
     * 配置时间规则
     */
    @Scheduled( cron = "0/20 * * * * ? ")
    public void analysis() throws ParseException {
        //业务逻辑
        String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        System.out.println("当前时间:"+time);
    }
    
}

CRON表达式

对于定时任务,我们使用的时候主要是注重两个方面,一个是定时任务的业务,另一个就是Cron表达式。

Cron 表达式支持到六个域 

名称是否必须允许值特殊字符
0-59 , - * /
0-59 , - * /
0-23 , - * /
1-31 , - * ? / L W C
1-12 或 JAN-DEC , - * /
1-7 或 SUN-SAT , - * ? / L C #

 

 

月份和星期的名称是不区分大小写的。FRI 和 fri 是一样的。

 

 

 

 

 

cron在线生成器地址:https://cron.qqe2.com/

定时统计

 

 

 

 

admin

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.tanhua.model.admin.Log;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

@Repository
public interface LogMapper extends BaseMapper<Log> {

    /**
     * 根据操作时间和类型统计日志统计用户数量
     *
     * @param type
     * @param logTime
     * @return
     */
    @Select("SELECT COUNT(DISTINCT user_id) FROM tb_log WHERE TYPE=#{type} AND log_time=#{logTime}")
    Integer queryByTypeAndLogTime(@Param("type") String type, @Param("logTime") String logTime);

    /**
     * 根据时间统计用户数量
     *
     * @param logTime
     * @return
     */
    @Select("SELECT COUNT(DISTINCT user_id) FROM tb_log WHERE log_time=#{logTime}")
    Integer queryByLogTime(String logTime);

    /**
     * 查询次日留存 , 从昨天活跃的用户中查询今日活跃用户
     *
     * @param today
     * @param yestoday
     * @return
     */
    @Select("SELECT COUNT(DISTINCT user_id)  FROM tb_log WHERE log_time=#{today} AND user_id IN (SELECT user_id FROM tb_log WHERE TYPE='0102' AND log_time=#{yestoday})")
    Integer queryNumRetention1d(@Param("today") String today, @Param("yestoday") String yestoday);
}

为了方便操作,可以通过以下单元测试方法。保存若干操作数据

import com.tanhua.manager.domain.Log;
import com.tanhua.manager.mapper.LogMapper;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Random;

@RunWith(SpringRunner.class)
@SpringBootTest
public class LogTest {

    @Autowired
    private LogMapper logMapper;
    
    private String logTime = "";

    //模拟登录数据
    public void testInsertLoginLog() {
        for (int i = 0; i < 5; i++) {
            Log log = new Log();
            log.setUserId((long)(i+1));
            log.setLogTime(logTime);
            log.setType("0101");
            logMapper.insert(log);
        }
    }

    //模拟注册数据
    public void testInsertRegistLog() {
        for (int i = 0; i < 10; i++) {
            Log log = new Log();
            log.setUserId((long)(i+1));
            log.setLogTime(logTime);
            log.setType("0102");
            logMapper.insert(log);
        }
    }
    //模拟其他操作
    public void testInsertOtherLog() {
        String[] types = new String[]{"0201","0202","0203","0204","0205","0206","0207","0301","0302","0303","0304"};
        for (int i = 0; i < 10; i++) {
            Log log = new Log();
            log.setUserId((long)(i+1));
            log.setLogTime(logTime);
            int index = new Random().nextInt(10);
            log.setType(types[index]);
            logMapper.insert(log);
        }
    }

    @Test
    public void generData() {
        testInsertLoginLog();
        testInsertRegistLog();
        testInsertOtherLog();
    }
}

 

 

 

 

  • 修改AnalysisTask类,调用service进行定时统计

@Component
public class AnalysisTask {

    @Autowired
    private AnalysisService analysisService;

    /**
     * 配置时间规则
     *   在学习测试时,可以将时间间隔设置相对短一些
     */
    @Scheduled( cron = "0/20 * * * * ? ")
    public void analysis() throws ParseException {
        //业务逻辑
        String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
        System.out.println("开始统计:"+time);
        //调logService完成日志统计
        analysisService.analysis();
        System.out.println("结束统计");
    }
}



配置AnalysisService

import
cn.hutool.core.date.DateUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.tanhua.admin.mapper.AnalysisMapper; import com.tanhua.admin.mapper.LogMapper; import com.tanhua.model.admin.Analysis; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.expression.ParseException; import org.springframework.stereotype.Service; import java.text.SimpleDateFormat; import java.util.Date; /** * @author Administrator */ @Service public class AnalysisService { @Autowired private AnalysisMapper analysisMapper; @Autowired private LogMapper logMapper; /** * 定时统计日志数据到统计表中 * 1、查询tb_log表中的数 (每日注册用户数,每日登陆用户,活跃的用户数据,次日留存的用户) * 2、构造AnalysisByDay对象 * 3、完成统计数据的更新或者保存 */ public void analysis() throws ParseException { //1、定义查询的日期 String todayStr = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); String yesdayStr = DateUtil.yesterday().toString("yyyy-MM-dd"); //2、统计数据-注册数量 Integer regCount = logMapper.queryByTypeAndLogTime("0102", todayStr); //3、统计数据-登录数量 Integer loginCount = logMapper.queryByTypeAndLogTime("0101", todayStr); //4、统计数据-活跃数量 Integer activeCount = logMapper.queryByLogTime(todayStr); //5、统计数据-次日留存 Integer numRetention1d = logMapper.queryNumRetention1d(todayStr, yesdayStr); //6、根据日期查询数据 QueryWrapper<Analysis> qw = new QueryWrapper<Analysis>(); qw.eq("record_date",new SimpleDateFormat("yyyy-MM-dd").parse(todayStr)); //7、构造Analysis对象 Analysis analysis = analysisMapper.selectOne(qw); //8、如果存在,更新,如果不存在保存 if(analysis != null) { analysis.setNumRegistered(regCount); analysis.setNumLogin(loginCount); analysis.setNumActive(activeCount); analysis.setNumRetention1d(numRetention1d); analysisMapper.updateById(analysis); }else { analysis = new Analysis(); analysis.setNumRegistered(regCount); analysis.setNumLogin(loginCount); analysis.setNumActive(activeCount); analysis.setNumRetention1d(numRetention1d); analysis.setRecordDate(new SimpleDateFormat("yyyy-MM-dd").parse(todayStr)); analysis.setCreated(new Date()); analysisMapper.insert(analysis); } } }

创建LogMapper并配置查询方法

 

posted @ 2022-01-14 20:16  互联.王  阅读(910)  评论(0编辑  收藏  举报