2019年7月19日 基于注解@Scheduled默认为单线程,任务的执行时机会受上一个任务执行时间的影响。

 

fixedRate配置了上一次任务的开始时间下一次任务的开始时间的间隔,每次任务都会执行;
fixedDelay配置了上一次任务的结束时间下一次任务的开始时间的间隔,每次任务都会执行;
cron表达式配置了在哪一刻执行任务,会在配置的任务开始时间判断任务是否可以执行,如果能则执行,不能则会跳过本次执行;
如果是强调任务间隔的定时任务,建议使用fixedRate和fixedDelay,如果是强调任务在某时某分某刻执行的定时任务,建议使用cron表达式。

这里使用fixedDelay的原因是:它的间隔时间是根据上次的任务结束的时候开始计时的,比如我这里设置的15分钟间隔,也就是意味着下次执行任务的时间开始计算是上次执行任务结束的时间,当时间间隔为15分钟时,再次开始执行该任务。

而fixedRate它的计算时间是根据上次任务开始的时间计时的,比如fixedRate设置的间隔时间为5秒,如果执行此任务所耗费的时间为3秒,那2任务结束后的两秒任务就会再次执行,但如果任务执行的时间超过了5秒,就会出现阻塞,具体有什么影响,目前我还没有测试,如果好奇的小伙伴可以自己动手试下

 

 

import io.renren.modules.generator.service.OfficialService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Component
@Configuration      //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling   // 2.开启定时任务
public class SaticScheduleTask {
    @Autowired
    private OfficialService officialService;
    //基于注解@Scheduled默认为单线程
    //3.添加定时任务
    //或直接指定时间间隔,例如:1秒(1000), 1分钟(60000)
    @Scheduled(fixedDelay=15*60*1000 )
    private void configureTasks() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hh:mm:ss");
        String data=sdf.format(new Date());
        System.err.println("获取并更新公众号用户列表定时任务,执行时间: " + data);
        System.err.println("数据获取开始时间: " + sdf.format(new Date()));
        officialService.getWXopenids(); //调用方法
        System.err.println("数据获取结束时间: " + sdf.format(new Date()));

    }
}

 

<!--定时任务添加依赖-->
<!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz -->
<dependency>
   <groupId>org.quartz-scheduler</groupId>
   <artifactId>quartz</artifactId>
   <version>2.3.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-context-support</artifactId>
   <version>5.1.0.RELEASE</version>
</dependency>

 

 

下面再提供一个批量导入的定时任务demo 

package cn.com.jala.retailer.manage.task;

import cn.com.jala.retailer.manage.dao.*;
import cn.com.jala.retailer.manage.entity.*;
import cn.com.jala.retailer.manage.util.SpringContextJobUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
@Component
@Configuration      //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling
@SuppressWarnings("unused")
public class SaticSaleTask  implements Job {


    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDataMap jobDataMap=jobExecutionContext.getJobDetail().getJobDataMap();

        String userCode=jobDataMap.get("userCode").toString();
        String inportTime=jobDataMap.get("inportTime").toString();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd hh:mm:ss");
        String data=sdf.format(new Date());
        System.err.println("获取定时任务,执行时间: " + data);
        System.err.println("数据获取开始时间: " + sdf.format(new Date()));
        batchInsert(userCode,inportTime);
        System.err.println("数据获取结束时间: " + sdf.format(new Date()));
    }


    /** 批量导入 */
    @Transactional(rollbackFor=Exception.class)
    public void batchInsert( String userCode,String inportTime){

        JrInportLogDao  jrInportLogDao = (JrInportLogDao) SpringContextJobUtil.getBean("jrInportLogDao");
        JrSaleTargetsDao  jrSaleTargetsDao = (JrSaleTargetsDao) SpringContextJobUtil.getBean("jrSaleTargetsDao");
        SysAccountDao  sysAccountDao = (SysAccountDao) SpringContextJobUtil.getBean("sysAccountDao");
        JrMaterialDao  jrMaterialDao = (JrMaterialDao) SpringContextJobUtil.getBean("jrMaterialDao");
        JrSaleTargetsTemporaryDao  jrSaleTargetsTemporaryDao = (JrSaleTargetsTemporaryDao) SpringContextJobUtil.getBean("jrSaleTargetsTemporaryDao");

        List<JrSaleTargets> saleTargetsList=jrSaleTargetsDao.getAll();
        List<SysAccount> accountList=sysAccountDao.getByCode("");
        List<JrMaterial> materialList=  jrMaterialDao.getByMatnr("");

        List<JrSaleTargetsTemporary> datalist=jrSaleTargetsTemporaryDao.getAll();


        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMMdd hh:mm:ss");
        String data2=sdf2.format(new Date());
        log.info(datalist.size()+"导入开始时间"+data2);
        HashMap<String,String> saleTargetsMap=new HashMap();
        HashMap<String,String> accountMap=new HashMap();
        HashMap<String,String> materialMap=new HashMap();

        materialList.forEach((item ->{ materialMap.put(item.getMatnr(),item.getMaktx());}));
        accountList.forEach((item ->{ accountMap.put(item.getCode(),item.getErpName());}));

        saleTargetsList.forEach((item2 ->{
            StringBuffer str=new StringBuffer();
            // 将代理商编码、物料编码、日期 作为key,id作为value
            str.append(item2.getAccountCode()+item2.getMaterialCode()+item2.getTime()+item2.getCategory());
            saleTargetsMap.put(str.toString(),item2.getId());}));


        SimpleDateFormat sdf = new SimpleDateFormat("yyyy");
        int dataStartRow = 3;
        List<JrSaleTargets> inertList=new ArrayList<>();
        List<String> ids=new ArrayList<>();
        List<JrInportLog> logList=new ArrayList<>();

        for(JrSaleTargetsTemporary item:datalist) {
            JrInportLog inportLog=new JrInportLog();


                    JrSaleTargets jrSaleTargets = new JrSaleTargets();
                    // 复制对象
                    BeanUtils.copyProperties(item, jrSaleTargets);


                    // 将代理商编码、物料编码、日期、品类 作为key,顺序要和前面的报错一致
                    StringBuffer skey=new StringBuffer();
                    skey.append(item.getAccountCode()+item.getMaterialCode()+item.getTime()+item.getCategory());
                    jrSaleTargets.setIsdelete(0);
                    jrSaleTargets.setCreateby(userCode);
                    jrSaleTargets.setCreatetime(new Date());
                    jrSaleTargets.setUpdateUser(userCode);
                    jrSaleTargets.setUpdateTime(new Date());
                    // 如果没有改key则新增数据,有则先删除后增加
                    if(!saleTargetsMap.isEmpty() && saleTargetsMap.containsKey(skey.toString())==true) {
                        if(!ids.contains(saleTargetsMap.get(skey.toString()))){
                            ids.add(saleTargetsMap.get(skey.toString()));
                        }

                    }
                    inertList.add(jrSaleTargets);
                dataStartRow++;
        }
        if(logList.size()>0){
            jrInportLogDao.insertBatch(logList);
            return ;
        }
        log.info("要删除的ids"+ids.size());
        if(ids.size()>0) {
            jrSaleTargetsDao.deleteByIds(ids);
        }
        List<List<JrSaleTargets>> list2=averageAssign(inertList,200);
        for(int i=0;i<list2.size();i++){
            jrSaleTargetsDao.insertBatch(list2.get(i));
        }
        jrInportLogDao.deleteAll();
        JrInportLog jrInportLog=new JrInportLog();
        jrInportLog.setCreateby(userCode);
        jrInportLog.setStatus("导入成功");
        try {
            jrInportLog.setCreateTime(sdf2.parse(inportTime));

        jrInportLog.setUpdateby(userCode);
        jrInportLog.setUpdateTime(sdf2.parse(inportTime));
        jrInportLog.setErrorRow("");
        jrInportLog.setErrorMsg("应导入:"+datalist.size()+"条,实际导入"+inertList.size()+"条");
        jrInportLogDao.insert(jrInportLog);
        jrSaleTargetsTemporaryDao.deleteAll();
        } catch (ParseException e) {
            e.printStackTrace();
        }
        log.info(data2+"导入结束时间"+sdf2.format(new Date()));
        log.info(inertList.size()+"销售指标导入成功");


    }

// 将list平分的工具类
    public static <JrSaleTargets> List<List<JrSaleTargets>> averageAssign(List<JrSaleTargets> source,int n){
        List<List<JrSaleTargets>> result=new ArrayList<List<JrSaleTargets>>();
        int remaider=source.size()%n;  //(先计算出余数)
        int number=source.size()/n;  //然后是商
        int offset=0;//偏移量
        for(int i=0;i<n;i++){
            List<JrSaleTargets> value=null;
            if(remaider>0){
                value=source.subList(i*number+offset, (i+1)*number+offset+1);
                remaider--;
                offset++;
            }else{
                value=source.subList(i*number+offset, (i+1)*number+offset);
            }
            result.add(value);
        }
        return result;
    }
}




/**
*以下是service层调用定时任务工具类处理
**/


    /** 批量导入 */
    @Transactional(rollbackFor=Exception.class)
    public JsonResult batchInsert2(List<jrSaleTargetsImportData> list){

        String userCode=AppContext.getCurrentUser().getCode();
        try {
            Scheduler sched = gSchedulerFactory.getScheduler();
            if(!sched.isShutdown()) {
                sched.shutdown();
            }

            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
            String time1= sf.format(new Date());

            // 生效时间
            Date effectivetime = strToDate(time1+" 12:00:00");
            // 失效时间
            Date invalidtime = strToDate(time1+" 14:00:01");
            boolean flag = belongCalendar(new Date(), effectivetime, invalidtime);
            if(flag==true){
                JsonResult jsonResult=new JsonResult();
                jsonResult.setCode("2");
                jsonResult.setMsg("12点-14点该功能暂停使用");
                return jsonResult;
            }

            /**
             * 这里业务逻辑处理
             * */

            
        //创建一个JobDetail实例,将该实例与HelloJob Class绑定
        SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time=time1+" 12:00:01";
        Date date=new Date();

        try {
            date= sdf1.parse(time);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        JobDetail jobDetail = JobBuilder.newJob(SaticSaleTask.class) // 设置执行类
                .withIdentity("定时导入","group1").build();
       JobDataMap jobDataMap=jobDetail.getJobDataMap();
       jobDataMap.put("userCode",userCode);
       jobDataMap.put("inportTime",sdf1.parse(sdf1.format(new Date())));


        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("myTrigger","group1") // 设定执行名称
                .startAt(date)
                .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInSeconds(10) //设定执行间隔
                        .withRepeatCount(0)  // 设置执行次数
                ).build();

            SchedulerFactory sfact = new StdSchedulerFactory();
            Scheduler scheduler = null;
            scheduler = sfact.getScheduler();
            scheduler.start();

            //需要将jobDetail和trigger传进去,并将jobDetail和trigger绑定在一起。
            scheduler.scheduleJob(jobDetail,trigger);

        } catch (Exception e) {
            jrSaleTargetsTemporaryDao.deleteAll();
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        
        return  JsonResult.success("success");
    }