想要实现的业务场景是:
不同的商家可以设置商品秒杀时间,每次执行完第一个商家的秒杀后,会开始准备执行下一个离目前时间最近的商家秒杀任务。
核心:
设置多个不同时间只用执行一次的定时任务。
核心代码,自动获取数据库中距离当前时间最近的秒杀任务开始准备执行 。
package com.shop.core.secKill.util;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shop.core.secKill.entity.VO.Cron;
import com.shop.core.secKill.mapper.CronMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import java.util.Date;
@Configuration
@EnableScheduling
public class CompleteScheduleConfig implements SchedulingConfigurer {
@Autowired
@SuppressWarnings("all")
private CronMapper cronMapper;
/**
* 执行定时任务.
*/
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
Cron cron1 = new Cron();//对数据进行缓存
Runnable task=new Runnable() {
/**
* 要定时执行的方法
*/
@Override
public void run() {
if (cron1.getId()!=null){
System.err.println("cron1.getId()=="+cron1.getId());
}else {
System.err.println("cron.getId()==null");
}
}
};
Trigger trigger=new Trigger() {
/**
* 调度实现的时间控制
*/
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
QueryWrapper<Cron> cronQueryWrapper = new QueryWrapper<>();//设置获取条件,每次获取最新的秒杀
cronQueryWrapper.orderByAsc("date");
cronQueryWrapper.last("limit 1");
Cron cron = cronMapper.selectOne(cronQueryWrapper);//gou
System.out.println("cron_id: "+cron.getId());
cron1.setNum(cron.getNum());
cron1.setGid(cron.getGid());
cron1.setId(cron.getId());
CronTrigger cronTrigger=new CronTrigger(cron.getCron());
cronMapper.deleteById(cron.getId());//删掉,让下一次更新最新的
return cronTrigger.nextExecutionTime(triggerContext);
}
};
//设置定时任务 //执行方法 //调用时间
taskRegistrar.addTriggerTask(task, trigger);
}
}
在run()
方法中可以调用别的方法,这里的只需要把参数传递出去即可;
以下为数据库以及插入修改内容的方法(根据自己需要自行修改)
/**
* 添加|修改秒杀任务
* @param secKillVO
* @return ResponseData<Object> 自己写的一个返回类型
*/
@Override
public ResponseData<Object> setSecKill(SecKillVO secKillVO, HttpServletRequest request){
final String[] s = secKillVO.getDate().toString().split(" ");
System.out.println(s[0]);
System.out.println(s[1]);
final String[] date = s[0].split("-");
final String[] time = s[1].split(":");
String mon = date[1];
String day = date[2];
String hour = time[0];
String min = time[1];
String sec = time[2];
final String sec1 = StringUtils.substring(sec, 0, 2);
String str_time = sec1+" "+min+" "+hour+" "+day+" "+mon+" ?";//设置的秒杀时间
Cron cron = new Cron();
try {
cron.setCron(str_time);
cron.setGid(secKillVO.getGoodsId());
cron.setNum(secKillVO.getNum());
cron.setDuring(secKillVO.getDuring());
cron.setDate(secKillVO.getDate());
final User loginUser = loginService.getLoginUser(request);//获取当前商户id
cron.setShopId(loginUser.getId());
final Cron gid = cronMapper.selectOne(WrapperUtils.getQueryWrapper("gid", secKillVO.getGoodsId()));
if (gid==null){//如果为空就添加秒杀,不为空就更新一下秒杀
cronMapper.insert(cron);
return Result.success("添加秒杀成功");
}
cronMapper.update(cron,WrapperUtils.getQueryWrapper("gid", secKillVO.getGoodsId()));
return Result.success("修改秒杀成功");
} catch (Exception e) {
e.printStackTrace();
return Result.error("添加秒杀失败");
}
}
上诉的代码定时器启动之后并不能实现手动的开启关闭
package com.shop.core.secKill.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.concurrent.ScheduledFuture;
/**
* 利用线程池实现任务调度
* Task任务调度器可以实现任务的调度和删除
* 原理:
* 实现一个类:ThreadPoolTaskScheduler线程池任务调度器,能够开启线程池进行任务调度
* ThreadPoolTaskScheduler.schedule()方法会创建一个定时计划ScheduleFuture,
* 在这个方法中添加两个参数一个是Runable:线程接口类,和CronTrigger(定时任务触发器)
* 在ScheduleFuture中有一个cancel可以停止定时任务
* @author Admin
*
* Scheduled Task是一种轻量级的任务定时调度器,相比于Quartz,减少了很多的配置信息,但是Scheduled Task
* 不适用于服务器集群,引文在服务器集群下会出现任务被多次调度执行的情况,因为集群的节点之间是不会共享任务信息的
* 每个节点的定时任务都会定时执行
*
*/
@RestController
@EnableScheduling
public class DynamicTaskController {
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
private ScheduledFuture future;
@Bean
public ThreadPoolTaskScheduler trPoolTaskScheduler(){
return new ThreadPoolTaskScheduler();
}
/**
* 1,定义一个方法实现定时任务的启动
* 2,定义一个方法实现用于终止定时任务
* 3,修改定时任务时间:changeCron
*/
/**
* 启动定时器
* @return
*/
@RequestMapping("startTest")
public String StartTest(){
/**
* task:定时任务要执行的方法
* trigger:定时任务执行的时间
*/
future=threadPoolTaskScheduler.schedule(new myRunable(),new CronTrigger("0/5 * * * * *") );
return "startTest";
}
/**
* 停止定时任务
* @return
*/
@RequestMapping("endTask")
public String endTask(){
if(future!=null){
future.cancel(true);
}
System.out.println("endTask");
return "endTask";
}
/**
* 改变调度的时间
* 步骤:
* 1,先停止定时器
* 2,在启动定时器
*/
@RequestMapping("changeTask")
public String changeTask(){
//停止定时器
endTask();
//定义新的执行时间
future=threadPoolTaskScheduler.schedule(new myRunable(),new CronTrigger("0/10 * * * * *") );
//启动定时器
// StartTest();
System.out.println("changeTask");
return "changeTask";
}
/**
* 定义定时任务执行的方法
* @author Admin
*
*/
public class myRunable implements Runnable{
@Override
public void run() {
System.out.println("定时任务要执行的方法111"+new Date());
}
}
}
补充一下别的秒杀
@Configuration //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class testTime { //3.添加定时任务
// @Scheduled(cron = "26 23 16 15 7 ?")//7月15号16点23分26秒
@Scheduled(cron = "0/2 * * * * ?")//从任意时间的0s开始,每2s执行一次
private void configureTasks() {
System.err.println("执行静态定时任务时间: " + LocalDateTime.now());
}