利用Quartz把数据库数据定时更新同步到Redis
- Job :表示一个工作,要执行的具体内容,此接口只有一个方法
void execute(JobExecutionContext context)
public class quartzJob implements Job{
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
.......
}
}
- JobDetail :表示一个具体的可执行的调度程序,job是这个可执行程调读程序所要执行的内容,另外JobDeail还包含了这个任务调读的方案和策略(执行job的调度程序,用于定义任务的实例)
- jobBuilder:用于定义/构建JobDetail实例
· // 3.创建JobDetail
JobDetail jobDetail = JobBuilder.newJob(quartzJob.class)
.withDescription("this is a ram job") //job的描述
.withIdentity("ramJob", "ramGroup") //job 的name和group
.build();
newJob 是JobBuilder静态导入的方法
//jobDetail信息
JobDetail 'group1.myJob': jobClass: 'emergency.prewarning.biz.quartz.entity.quartz.entity.min5RunTask concurrentExectionDisallowed: true persistJobDataAfterExecution: false isDurable: false requestsRecovers: false
- Trigger :触发器 代表一个调度参数的配置,什么时候去调,编写一个触发器,当进行delete,update时触发
- TriggerBuilder:用于定义/构建Trigger触发器
// 4.创建Trigger触发器
Trigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("ramTrigger", "ramTriggerGroup")
.startAt(new Date()) // 默认当前时间启动
.withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")) // 两秒执行一次
.build();
- CronScheduleBuilder.cronSchedule(cron):传入cron表达式规定任务执行时间
// 表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder =CronScheduleBuilder.cronSchedule(cronExpression);
- Scheduler:代表一个调度容器,一个调度容器中可以注册多个JobDetail和Trigger。当Trigger与JobDetail组合 ,就可以被Scheduler容器调度了(与调度程序交互的主要API)
//创建方式1:scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//创建方式2:scheduler
SchedulerFactory sfact = new StdSchedulerFactory();
Scheduler scheduler = sfact.getScheduler();
scheduler.scheduleJob(jobDetail, trigger);
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--postgresql-->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.8</version>
</dependency>
<!-- mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.2</version>
</dependency>
<!--Excel-->
<dependency>
<groupId>org.jeecgframework</groupId>
<artifactId>autopoi-web</artifactId>
<version>1.0.3</version>
<exclusions>
<exclusion>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--quartz-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!--redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--redis要依赖此包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.20</version>
</dependency>
对象序列化
private static final long serialVersionUID = 1L;
JAVA序列化的机制是通过判断类的serialVersionUID来验证的版本一致的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID于本地相应实体类的serialVersionUID进行比较。如果相同说明是一致的,可以进行反序列化,否则会出现反序列化版本一致的异常,即是InvalidClassException3。
Mybatis-plus自动生成mysql的UUId
1.修改entity的代码如上,生成getter and setter
2.修改数据库的数据类型为varchar(36)
/**
* @Description: 定时任务在线管理
* @Author: jeecg-boot
* @Date: 2019-01-02
* @Version: V1.0
*/
@Data
@TableName("sys_quartz_job")
public class QuartzJob implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@TableId(type = IdType.UUID)
private String id;
/**
* 创建人
*/
private String createBy;
/**
* 创建时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss") //出参时间格式
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") //传入参数时间格式
private java.util.Date createTime;
/**
* 删除状态
*/
private Integer delFlag;
/**
* 修改人
*/
private String updateBy;
/**
* 修改时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private java.util.Date updateTime;
/**
* 任务类名
*/
@Excel(name = "任务类名", width = 40)
private String jobClassName;
/**
* cron表达式
*/
@Excel(name = "cron表达式", width = 30)
private String cronExpression;
/**
* 参数
*/
@Excel(name = "参数", width = 15)
private String parameter;
/**
* 描述
*/
@Excel(name = "描述", width = 40)
private String description;
/**
* 状态 0正常 -1停止
*/
@Excel(name = "状态", width = 15)
private Integer status;
}
@Excel
<dependency>
<groupId>org.jeecgframework</groupId>
<artifactId>autopoi-web</artifactId>
<version>1.0.3</version>
<exclusions>
<exclusion>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</exclusion>
</exclusions>
</dependency>
定时任务在线管理
/**
* @Description: 定时任务在线管理
*/
@Slf4j
@Service
public class QuartzJobServiceImpl extends ServiceImpl<QuartzJobMapper, QuartzJob> implements IQuartzJobService {
@Resource
private QuartzJobMapper quartzJobMapper;
@Autowired
private Scheduler scheduler;
/**
* Job工作任务,反射进行实例化,同new对象
* @param classname
* @return
* @throws Exception
*/
private static Job getClass(String classname) throws Exception {
Class<?> class1 = Class.forName(classname);
return (Job) class1.newInstance();
}
/**
* 数据库查找工作任务名
* @param jobClassName
* @return
*/
@Override
public List<QuartzJob> findByJobClassName(String jobClassName) {
return quartzJobMapper.findByJobClassName(jobClassName);
}
/**
* 保存&启动定时任务
*/
@Override
public boolean saveAndScheduleJob(QuartzJob quartzJob) {
if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) {
// 定时器添加
this.schedulerAdd(quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter());
}
// DB设置修改
quartzJob.setDelFlag(CommonConstant.DEL_FLAG_0);
return this.save(quartzJob);
}
/**
* 恢复定时任务
*/
@Override
public boolean resumeJob(QuartzJob quartzJob) {
schedulerDelete(quartzJob.getJobClassName().trim());
schedulerAdd(quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter());
quartzJob.setStatus(CommonConstant.STATUS_NORMAL);
return this.updateById(quartzJob);
}
/**
* 编辑&启停定时任务
*
* @throws SchedulerException
*/
@Override
public boolean editAndScheduleJob(QuartzJob quartzJob) throws SchedulerException {
if (CommonConstant.STATUS_NORMAL.equals(quartzJob.getStatus())) {
schedulerDelete(quartzJob.getJobClassName().trim());
schedulerAdd(quartzJob.getJobClassName().trim(), quartzJob.getCronExpression().trim(), quartzJob.getParameter());
} else {
scheduler.pauseJob(JobKey.jobKey(quartzJob.getJobClassName().trim()));
}
return this.updateById(quartzJob);
}
/**
* 删除&停止删除定时任务
*/
@Override
public boolean deleteAndStopJob(QuartzJob job) {
schedulerDelete(job.getJobClassName().trim());
boolean ok = this.removeById(job.getId());
return ok;
}
/**
* 添加定时任务
*
* @param jobClassName
* @param cronExpression
* @param parameter
*/
private void schedulerAdd(String jobClassName, String cronExpression, String parameter) {
try {
// 启动调度器
scheduler.start();
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(getClass(jobClassName).getClass()).withIdentity(jobClassName).usingJobData("parameter", parameter).build();
// 表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
throw new JeecgBootException("创建定时任务失败", e);
} catch (RuntimeException e) {
throw new JeecgBootException(e.getMessage(), e);
} catch (Exception e) {
throw new JeecgBootException("后台找不到该类名:" + jobClassName, e);
}
}
/**
* 删除定时任务
*
* @param jobClassName
*/
public void schedulerDelete(String jobClassName) {
try {
scheduler.pauseTrigger(TriggerKey.triggerKey(jobClassName));//停止触发器
scheduler.unscheduleJob(TriggerKey.triggerKey(jobClassName));//删除触发器
scheduler.deleteJob(JobKey.jobKey(jobClassName));//删除任务
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new JeecgBootException("删除定时任务失败");
}
}
线程任务服务
0 /30 * * * ? 和 0 0/30 * * *?区别
- 0 /30 * * * ? 代表从项目启动后开始计算 例: 17:24启动项目 那么会在17:54开始执行
- 0 0/30 * * *? 代表本地时间开始计算 例: 17:24启动项目 那么会在17:30开始执行
@Service
public class CustomMultiThreadingService {
@Resource
private IQuartzJobService quartzJobService;
/**
* @Description:30min数据同步
*/
public void min30RunTask() {
QuartzJob quartzJob = new QuartzJob();
quartzJob.setStatus(0); //设置为正常
quartzJob.setCreateBy("1"); //创建人
quartzJob.setCronExpression("0 /30 * * * ?"); //cron表达式
quartzJob.setId("1");
quartzJob.setJobClassName("emergency.prewarning.biz.quartz.entity.Min30RunTaskQuartz");//job任务路径
quartzJob.setParameter("Min30RunTaskQuartz");
quartzJobService.resumeJob(quartzJob); //恢复定时任务
}
}
Job工作任务
@Slf4j
@DisallowConcurrentExecution //禁止并发执行
public class min5RunTask implements Job {
@Resource
private QuartzCommonService quartzCommonService;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
quartzCommonService.min5RunTask();
}
}
判断数据库中是否有该表
@Slf4j
@Service
public class QuartzCommonServiceimpl implements QuartzCommonService {
@Resource
private SelectTableNameMapper selectTableNameMapper;
@Resource
private RedisUtil redisUtil;
private int ret = 0;
@Override
public void min5RunTask() {
System.out.println("*************2分钟同步一次开始**************");
ret = selectTableName("fruits");
if (ret > 0) {
//判断redis是否有该表
List<Map<String, Object>> fruits = selectTableNameMapper.queryFruits();
if (fruits.size() > 0) {
redisUtil.del("fruits"); //先删除redis中该表数据
redisUtil.set("fruits", fruits); //再把该表存入redis中
}
}
System.out.println("*************2分钟同步一次结束**************");
}
public int selectTableName(String tableName) {
return selectTableNameMapper.queryTable(tableName);
}
}
ApplicationRunner
开发过程中,容器启动的时候需要去执行一些工程
@Component 普通的pojo实例化到spring容器中,相当于配置文件中的组件
@Component
public class QuartzController implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
// 30min数据同步redis
customMultiThreadingService.min30RunTask();
// 10min数据同步redis
customMultiThreadingService.min10RunTask();
// 5min数据同步redis
customMultiThreadingService.min5RunTask();
// 10s数据同步redis
customMultiThreadingService.s10RunTask();
}
}
Quartz默认提供12张表
- qrtz_blob_triggers : 以Blob 类型存储的触发器。
- qrtz_calendars :存放日历信息, quartz可配置一个日历来指定一个时间范围。
- qrtz_cron_triggers :存放cron类型的触发器。
- qrtz_fired_triggers :存放已触发的触发器
- qrtz_job_details :存放一个jobDetail信息
- qrtz_job_listeners :job监听器。
- qrtz_locks :存储程序的悲观锁的信息(假如使用了悲观锁)。
- qrtz_paused_trigger_graps :存放暂停掉的触发器
- qrtz_scheduler_state:调度器状态。
- qrtz_simple_triggers:简单触发器的信息
- qrtz_trigger_listeners:触发器监听器。
- qrtz_triggers:触发器的基本信息。