上一篇中我们说明了Springboot实现定时器quartz中文文档说明,
在开写主要内容前,我们来说明其他方式。
两者都是针对较简单的情况下。其一是,SpringBoot自带定时注解。其二是,定时线程池。
关于利用这两者前面已经实现、介绍过了,也给出(所有的只是为了更好的理解定时器)。
另外再讲一个自带的Timer来帮助理解(这三个都是三个基于线程来实现的)。
package com.cun;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class MyTimer extends Thread{
private Long time ;
public MyTimer(Long time) {
this.time = time;
}
@Override
public void run() {
while(true){
try {
TimeUnit.SECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
send();
}
}
/**
* 开始执行任务
*/
public void execute(){
this.start();
}
/**
* 定时任务
*/
private void send() {
System.out.println("任务执行了:" + new Date());
}
public static void main(String[] args) {
MyTimer myTimer = new MyTimer(2L); // 2 + L 表示2为long的数
myTimer.execute();
}
}
运行结果:(我们可以看到基于线程实现的)
就像上面我们实现的一样。JDK已经有了这么类java.util.Timer;是这样定时器的功能。
package com.cun;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class TimerTest {
public static void main(String[] args) {
Timer timer = new Timer();
// new Date() 马上执行任务,每隔1000执行一次,new Date()换成其他的就可以延迟执行
timer.scheduleAtFixedRate(new MyTask(), new Date(), 1000);
}
}
// 定时任务,这是一个线程
class MyTask extends TimerTask {
@Override
public void run() {
System.out.println("task execute ");
}
}
以下运行结果就不给出了。
利用newScheduledThreadPool线程池,效率是很可以的(多任务也能执行)。
package com.cun;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MyNewScheduledThreadPool {
public static void main(String[] args) throws InterruptedException,ExecutionException{
ScheduledExecutorService service = Executors.newScheduledThreadPool(4);
service.scheduleAtFixedRate(()->{ // 以固定的(频率)时间执行任务
try {
TimeUnit.MICROSECONDS.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
}, 0, 1000000, TimeUnit.MICROSECONDS); // 从0(马上执行),之后每隔1000000毫秒执行一次。
}
}
SpringBoot自带的(适合简单的定时任务)
package com.cun;
import java.util.Date;
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.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = VsCodeApplication.class)
@EnableScheduling // 开启定时任务注解(这必须打开)
public class VsCodeApplicationTests {
/*
* @Autowired private RedisTemplate redisTemplate;
*/
// 测试添加
@Test
@Scheduled(initialDelay=1000, fixedRate=5000) // 第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次
public void redisTest() {
System.out.println("ok----------------" + new Date());
}
}
接下来便是主要内容(上面的是一次性执行,中途很难改变操作,面对复杂的调度,还是quartz):
上一篇介绍了很多,先来写个小程序,明白它的大致流程是怎么操作的。
package com.cun;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 三要素之一,实现一共7步
* @author zy962
*
*/
// 1,创建MyJob
public class MyJob implements Job {
private Logger Logger = LoggerFactory.getLogger(getClass());
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
// 取出任务名
JobDetail detail = context.getJobDetail();
String name = detail.getJobDataMap().getString("name");
Logger.info("开始执行:" + new Date());
myTestTask();
}
// 调用你的业务层代码。
private void myTestTask() {
System.out.println("任务执行:" + new Date());
}
public static void main(String[] args) throws InterruptedException {
// 2,创建工厂
SchedulerFactory schedulerfactory = new StdSchedulerFactory();
Scheduler scheduler = null;
try {
// 2.1,通过schedulerFactory获取一个调度器
scheduler = schedulerfactory.getScheduler();
// 3,通过JobBuilder创建 JobDetail,指明job的名称,所在组的名称,以及绑定job类
JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("JobName", "JobGroupName")
.usingJobData("name", "quartz").build();
// 4,通过TriggerBuilder创建trigger,并定义触发的条件,立即触发,每3秒重复一次
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("CronTrigger1", "CronTriggerGroup")
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever())
.startNow().build();
// 5,把作业job和触发器注册到任务调度中
scheduler.scheduleJob(job, trigger);
// 6,启动调度
scheduler.start();
Thread.sleep(10000);
// 7,停止调度
scheduler.shutdown();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
运行结果:(大致就这七个过程,其他的操作都是通过key去更改调度的规则,这样方便我们图形界面的操作,而不是有需求要去改后台屎山代码,并且还可以持久化你的操作)
另外补充一段代码:(/QuartzJobBean 有源码可以知道本质上还是Job差不多,这种方式可以避免不能注入bean的问题)
package com.taotao.store.order.job;
import org.joda.time.DateTime;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
import com.taotao.store.order.mapper.OrderMapper;
/**
* 扫描超过2天未付款的订单关闭
*/
public class PaymentOrderJob extends QuartzJobBean {
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
ApplicationContext applicationContext = (ApplicationContext) context.getJobDetail().getJobDataMap()
.get("applicationContext");
//时间参数,当前时间向前推2天
applicationContext.getBean(OrderMapper.class).paymentOrderScan(new DateTime().minusDays(2).toDate());
}
}
构建场景:定时器简单每天定时查询数据库(操作你可以任意,随你喜欢,写得有点乱,但是还是说明了该说明的东西,这里提供一个思路如果想要耦合性高建议用反射调用)
下载包。对应版本,找到你所对应的数据库的sql,文件导入执行即可。
共11张表。
另外新建一张表qrtz_task_info用于存放定时任务基本信息和描述等信息
create table qrtz_task_info(
task_id SERIAL primary key,
job_name VARCHAR(120) NOT NULL,
job_group VARCHAR(120) NOT NULL,
job_class_name VARCHAR(120) NOT NULL,
trigger_name VARCHAR(120) NOT NULL,
trigger_group VARCHAR(120) NOT NULL,
create_date VARCHAR(120) NOT NULL
);
// 建表是少建了一个字段。
alter table qrtz_task_info add cron VARCHAR(120);
数据库表对应的实体类:
package com.cun.quartz;
import java.util.Date;
import lombok.Data;
@Data
public class QuartzPojo {
private Integer taskId;
private String jobName;
private String jobGroup;
private String jobClassName;
private String triggerName;
private String triggerGroup;
private String corn; // 这个字段和数据库不一致,要额外注意
private Date createDate;
}
对应的mapper.xml
insert into qrtz_task_info
values(#{taskId},
#{jobName},
#{jobGroup},
#{jobClassName},
#{triggerName},
#{triggerGroup},
#{createDate},
#{corn})
对应mapper
package com.cun.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Mapper;
import com.cun.quartz.QuartzPojo;
// mapper注解一定要有
@Mapper
public interface JobAndTriggerMapper {
public List getAllInfo() throws Exception;
// 在设定的是时间下插入数据
public void addPojo(QuartzPojo pojo) throws Exception;
}
service层逻辑:(接口就不给出了很简单)
package com.cun.serviceImpl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.cun.mapper.JobAndTriggerMapper;
import com.cun.quartz.QuartzPojo;
import com.cun.service.JobAndTriggerService;
@Service
public class JobAndTriggerServiceImpl implements JobAndTriggerService {
@Autowired
private JobAndTriggerMapper mapper;
@Override
public List getAllInfo(QuartzPojo pojo) throws Exception {
//addPojo(pojo); // 第一次打开插入数据,后面注释掉
System.out.println("开始查询");
List list = mapper.getAllInfo();
System.out.println(list);
return list;
}
@Override
public void addPojo(QuartzPojo pojo) throws Exception {
mapper.addPojo(pojo);
}
}
定时任务类:
package com.cun.conf;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.cun.mapper.JobAndTriggerMapper;
public class MyQuartzTask implements Job {
@Autowired
private JobAndTriggerMapper mapper;
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException {
logger.info("任务开始执行");
myTestTask();
logger.info("任务已经执行结束");
}
/**
* 业务层代码
*/
public void myTestTask() {
try {
logger.info("------------------------------开始");
mapper.getAllInfo();
} catch (Exception e) {
e.printStackTrace();
}
}
}
我们的quartz工具类:
package com.cun.conf;
import java.util.Map;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 定时任务工具类
* @author zy962
*
*/
@Component
public class QuartzManagerUtil {
/**
* 注入任务调度器
*/
@Autowired
private Scheduler scheduler;
private static String JOB_GROUP_NAME = "ATAO_JOBGROUP"; //任务组
private static String TRIGGER_GROUP_NAME = "ATAO_TRIGGERGROUP"; //触发器组
/**
* 启动所有定时任务
*/
public void startJobs() {
try {
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名
*
* @param jobName 任务名
* @param cls 任务
* @param time 时间设置,参考quartz说明文档
*/
public void addJob(String jobName, Class extends Job> cls, String time) {
try {
JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(jobName, JOB_GROUP_NAME).build(); //用于描叙Job实现类及其他的一些静态信息,构建一个作业实例
CronTrigger trigger = TriggerBuilder
.newTrigger() //创建一个新的TriggerBuilder来规范一个触发器
.withIdentity(jobName, TRIGGER_GROUP_NAME) //给触发器起一个名字和组名
.withSchedule(CronScheduleBuilder.cronSchedule(time))
.build();
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
scheduler.start(); // 启动
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名 (带参数)
*
* @param jobName 任务名
* @param cls 任务
* @param time 时间设置,参考quartz说明文档
*/
public void addJob(String jobName, Class extends Job> cls, String time, Map parameter) {
try {
JobDetail jobDetail = JobBuilder.newJob(cls).withIdentity(jobName, JOB_GROUP_NAME).build(); //用于描叙Job实现类及其他的一些静态信息,构建一个作业实例
jobDetail.getJobDataMap().put("parameterList", parameter); //传参数
CronTrigger trigger = TriggerBuilder
.newTrigger() //创建一个新的TriggerBuilder来规范一个触发器
.withIdentity(jobName, TRIGGER_GROUP_NAME) //给触发器起一个名字和组名
.withSchedule(CronScheduleBuilder.cronSchedule(time))
.build();
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
scheduler.start(); // 启动
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 添加一个定时任务
*
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param jobClass 任务
* @param time 时间设置,参考quartz说明文档
*/
public void addJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName, Class extends Job> jobClass,
String time) {
try {
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();// 任务名,任务组,任务执行类
CronTrigger trigger = TriggerBuilder // 触发器
.newTrigger()
.withIdentity(triggerName, triggerGroupName)
.withSchedule(CronScheduleBuilder.cronSchedule(time))
.build();
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
scheduler.start(); // 启动
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 添加一个定时任务 (带参数)
*
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param jobClass 任务
* @param time 时间设置,参考quartz说明文档
*/
public void addJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName, Class extends Job> jobClass,
String time, Map parameter) {
try {
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).build();// 任务名,任务组,任务执行类
jobDetail.getJobDataMap().put("parameterList", parameter); //传参数
CronTrigger trigger = TriggerBuilder // 触发器
.newTrigger()
.withIdentity(triggerName, triggerGroupName)
.withSchedule(CronScheduleBuilder.cronSchedule(time))
.build();
scheduler.scheduleJob(jobDetail, trigger);
if (!scheduler.isShutdown()) {
scheduler.start(); // 启动
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)
*
* @param jobName 任务名
* @param time 新的时间设置
*/
public void modifyJobTime(String jobName, String time) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME); //通过触发器名和组名获取TriggerKey
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); //通过TriggerKey获取CronTrigger
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
JobKey jobKey = JobKey.jobKey(jobName, JOB_GROUP_NAME); //通过任务名和组名获取JobKey
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
Class extends Job> objJobClass = jobDetail.getJobClass();
removeJob(jobName);
addJob(jobName, objJobClass, time);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 修改一个任务的触发时间
*
* @param triggerName 任务名称
* @param triggerGroupName 传过来的任务名称
* @param time 更新后的时间规则
*/
public void modifyJobTime(String triggerName, String triggerGroupName, String time) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName); //通过触发器名和组名获取TriggerKey
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); //通过TriggerKey获取CronTrigger
if (trigger == null) return;
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(trigger.getCronExpression());
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(time)) {
trigger = (CronTrigger) trigger.getTriggerBuilder() //重新构建trigger
.withIdentity(triggerKey)
.withSchedule(scheduleBuilder)
.withSchedule(CronScheduleBuilder.cronSchedule(time))
.build();
scheduler.rescheduleJob(triggerKey, trigger); //按新的trigger重新设置job执行
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 移除一个任务(使用默认的任务组名,触发器名,触发器组名)
*
* @param jobName 任务名称
*/
public void removeJob(String jobName) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, TRIGGER_GROUP_NAME); //通过触发器名和组名获取TriggerKey
JobKey jobKey = JobKey.jobKey(jobName, JOB_GROUP_NAME); //通过任务名和组名获取JobKey
scheduler.pauseTrigger(triggerKey); // 停止触发器
scheduler.unscheduleJob(triggerKey);// 移除触发器
scheduler.deleteJob(jobKey); // 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 移除一个任务
*
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
*/
public void removeJob(String jobName, String jobGroupName, String triggerName, String triggerGroupName) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName); //通过触发器名和组名获取TriggerKey
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName); //通过任务名和组名获取JobKey
scheduler.pauseTrigger(triggerKey); // 停止触发器
scheduler.unscheduleJob(triggerKey);// 移除触发器
scheduler.deleteJob(jobKey); // 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 关闭所有定时任务
*/
public void shutdownJobs() {
try {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
插入数据以及定时任务添加:
package com.cun.conf;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.cun.quartz.QuartzPojo;
import com.cun.serviceImpl.JobAndTriggerServiceImpl;
@Component // 这个注解没什么意义可以删掉
public class QuartzSelect {
public void timeTask() throws Exception {
String jobName = "我的Quartz测试";
String className = "com.cun.conf.MyQuartzTask";
Class cls = Class.forName(className);
String time = "0 46 23 ? * *"; // 每天23:30执行
// 测试用数据
QuartzPojo pojo = new QuartzPojo();
pojo.setCorn(time);
pojo.setCreateDate(new Date());
pojo.setJobClassName(jobName);
pojo.setJobGroup("myGroup");
pojo.setTaskId(112);
pojo.setTriggerGroup("triggerGroup");
pojo.setTriggerName("triggerName");
pojo.setJobName("myName");
// SpringUtils.getBean(JobAndTriggerServiceImpl.class)不能自动注入的解决方式
JobAndTriggerServiceImpl service = SpringUtils.getBean(JobAndTriggerServiceImpl.class);
service.getAllInfo(pojo);
QuartzManagerUtil qManagerUtil = (QuartzManagerUtil) SpringUtils.getBean(QuartzManagerUtil.class);
qManagerUtil.addJob(jobName, cls, time);
}
}
主类:
package com.cun;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableScheduling;
import com.cun.conf.QuartzSelect;
import com.cun.conf.SpringUtils;
@SpringBootApplication
@MapperScan("com.cun.mapper")
@Import(SpringUtils.class) // 这个的作用解决不能自动注入
// @ComponentScan({"service"})
@EnableScheduling // 标注定时开启
public class VsCodeApplication {
public static void main(String[] args) {
SpringApplication.run(VsCodeApplication.class, args);
try {
new QuartzSelect().timeTask();
} catch (Exception e) {
e.printStackTrace();
}
}
}
解决不能自动注入问题:
package com.cun.conf;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
/**
* 解决无法注入问题
* @author zy962
*
*/
public final class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
if (SpringUtils.applicationContext == null) {
SpringUtils.applicationContext = applicationContext;
}
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过类名称获取Bean.
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
//通过class获取Bean.
public static T getBean(Class clazz){
return getApplicationContext().getBean(clazz);
}
}
数据库结果:
运行log:(可以看到定时任务启动,结束等关键日志(以提取出关键))
// 定时器启动
2019-07-02 23:44:30 [main] INFO org.quartz.core.QuartzScheduler -Scheduler quartzScheduler_$_NON_CLUSTERED started.
// 不定时检测是否触发trigger
2019-07-02 23:44:30 [quartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread -batch acquisition of 0 triggers
2019-07-02 23:44:55 [quartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread -batch acquisition of 0 triggers
2019-07-02 23:45:22 [quartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread -batch acquisition of 0 triggers
// 触发trigger
2019-07-02 23:45:46 [quartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread -batch acquisition of 1 triggers
2019-07-02 23:46:00 [quartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread -batch acquisition of 0 triggers
// 调用你的job任务
2019-07-02 23:46:00 [quartzScheduler_Worker-1] DEBUG org.quartz.core.JobRunShell -Calling execute on job ATAO_JOBGROUP.我的Quartz测试
// 任务开始执行
2019-07-02 23:46:00 [quartzScheduler_Worker-1] INFO com.cun.conf.MyQuartzTask -任务开始执行
2019-07-02 23:46:00 [quartzScheduler_Worker-1] INFO com.cun.conf.MyQuartzTask -------------------------------开始
2019-07-02 23:46:00 [quartzScheduler_Worker-1] DEBUG org.mybatis.spring.SqlSessionUtils -Creating a new SqlSession
2019-07-02 23:46:00 [quartzScheduler_Worker-1] DEBUG org.mybatis.spring.SqlSessionUtils -SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2cb9faad] was not registered for synchronization because synchronization is not active
2019-07-02 23:46:00 [quartzScheduler_Worker-1] DEBUG org.springframework.jdbc.datasource.DataSourceUtils -Fetching JDBC Connection from DataSource
2019-07-02 23:46:00 [quartzScheduler_Worker-1] DEBUG org.mybatis.spring.transaction.SpringManagedTransaction -JDBC Connection [org.postgresql.jdbc.PgConnection@7c369270] will not be managed by Spring
2019-07-02 23:46:00 [quartzScheduler_Worker-1] DEBUG com.cun.mapper.JobAndTriggerMapper.getAllInfo -==> Preparing: SELECT task_id, job_name, job_group, job_class_name, trigger_name, trigger_group, create_date, cron FROM qrtz_task_info
2019-07-02 23:46:00 [quartzScheduler_Worker-1] DEBUG com.cun.mapper.JobAndTriggerMapper.getAllInfo -==> Parameters:
2019-07-02 23:46:00 [quartzScheduler_Worker-1] DEBUG com.cun.mapper.JobAndTriggerMapper.getAllInfo -<== Total: 1
2019-07-02 23:46:00 [quartzScheduler_Worker-1] DEBUG org.mybatis.spring.SqlSessionUtils -Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@2cb9faad]
// 任务已经执行结束
2019-07-02 23:46:00 [quartzScheduler_Worker-1] INFO com.cun.conf.MyQuartzTask -任务已经执行结束
2019-07-02 23:46:29 [quartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread -batch acquisition of 0 triggers
感悟:写定时器遇到了很多的坑!但最搭的问题是一开始就想写个很复杂的定时任务。碰了一身灰,这就说明“万丈高楼平地起”真的没有错。我改变自己的想法,从最根本的定时任务开始分析,然后写一个小的demo运行成功。那么就下来就会简单很多,只需要你将demo中功能抽出建成帮助类,目标类,实现类等即可完成。这也让我想到前段时间写权限框架时的问题,自己设计了一个超级复杂的权限,导致最后逻辑理不清楚,还在都还在理其中的逻辑(笨蛋)。