定时器任务处理(xxlJob,定时器,延迟任务等)
对于生活中会存在一些任务,当时不做处理,我们可以通过定时任务的方式去处理一些任务,此文就是一个操作记录的流程记录,可以做到一下几点;
1.处理时间的设定
2.处理次数的设定
3.处理结果的记录
相对而言项目中非常使用.
做一个记录使用;
1.example
表结构
CREATE TABLE `tasks` (
`id` int(11) NOT NULL COMMENT '主键 id',
`business_id` varchar(30) NOT NULL COMMENT '业务关联键',
`business_type` int(11) DEFAULT NULL COMMENT '业务类型',
`create_user` varchar(255) DEFAULT NULL COMMENT '创建人',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`update_user` varchar(255) DEFAULT NULL COMMENT '更新人',
`update_time` timestamp NULL DEFAULT NULL COMMENT '更新时间',
`deal_time` timestamp NULL DEFAULT NULL COMMENT '处理时间',
`next_deal_time` timestamp NULL DEFAULT NULL COMMENT '下次处理时间',
`deal_count` int(255) DEFAULT NULL COMMENT '处理次数\r\n',
`status` int(11) DEFAULT NULL COMMENT '状态(0.待处理 1.处理中 2.处理失败 3 处理完成)',
`remark` varchar(255) DEFAULT NULL COMMENT '备注信息',
`active` int(1) DEFAULT NULL COMMENT '是否有效(0.逻辑删除 1 存在)',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
2.TasksTest-测试(可以直接使用job,或者定时器等调用)-
package com.controller;
import com.service.job.BusinessJobService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author syh
* @date 2023/6/9 11:03
* @details 类描述
*/
@SpringBootTest
public class TasksTest {
@Autowired
private BusinessJobService businessJobService;
@Test
public void process(){
businessJobService.dealTaskByType("1");
}
}
3.BusinessJobService-任务实现
package com.service.job;
/**
* @author syh
* @date 2023/6/8 10:05
* @details 类描述
*/
public interface BusinessJobService {
/**
* 获取对应类型的实现
*
* @param type
*/
void dealTaskByType(String type);
}
package com.service.job.impl;
import com.pojo.Tasks;
import com.service.job.BusinessJobService;
import com.service.dealer.Dealer;
import com.service.job.TasksTypeEnum;
import com.service.student.StudentService;
import com.service.task.TasksService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import javax.annotation.PostConstruct;
import javax.naming.Context;
import java.util.*;
/**
* @author syh
* @date 2023/6/8 10:11
* @details 类描述
*/
@Service
@Slf4j
public class BusinessJobServiceImpl implements BusinessJobService {
@Autowired
private TasksService tasksService;
private Map<TasksTypeEnum, Dealer> dealerMap=new HashMap<>();
@Autowired
private List<Dealer> dealerList; //获取所有的实现类
@PostConstruct
public void init() {
//这种方式自动维护,当然也可以使用map每次都添加也是可以的
for (Dealer dealer : dealerList) {
//map定义枚举,维护枚举更好的定义规则,也可以用数字或者字符代替
dealerMap.put(dealer.getTasksTypeEnum(), dealer);
}
}
/**
* 获取对应类型的实现
*
* @param type
*/
@Override
public void dealTaskByType(String type) {
//获取对应任务(也可以不指定type做通用,通过对nextDealTime的设定实现想要的结果,这样就可以一对多,也可以定义多个type)
List<Tasks> tasksList = tasksService.getTasksByType(type);
if (!CollectionUtils.isEmpty(tasksList)) {
for (Tasks tasks : tasksList) {
//设置任务状态,避免安全问题
boolean flag = tasksService.processTasks(tasks);
if (flag) {
//执行待执行的任务 实现对应的实现
boolean result = doDeal(tasks);
//处理执行完的任务
tasksService.endTasks(result, tasks);
}
}
}
}
/**
* 获取业务同时执行
*
* @param tasks
* @return
*/
private boolean doDeal(Tasks tasks) {
// 获取对应的实现类
Dealer dealer = dealerMap.get(TasksTypeEnum.getTasksTypeEnum(tasks.getBusinessType()));
boolean result = false;
try {
if (!ObjectUtils.isEmpty(dealer)) {
result = dealer.doDeal(tasks);
}
} catch (Exception e) {
log.info("业务处理异常");
return false;
}
return result;
}
private Dealer getDealer(Integer businessType) {
Dealer dealer = dealerMap.get(businessType);
return dealer;
}
}
4.TasksService-task任务记录
package com.service.task;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pojo.Tasks;
import java.util.List;
/**
* <p>
* 服务类
* </p>
*
* @author itcast
* @since 2023-06-08
*/
public interface TasksService extends IService<Tasks> {
/**
* 创建任务
*
* @param tasks
*/
public void createTasks(Tasks tasks);
/**
* 根据类型获取tasks
*
* @param type
* @return
*/
List<Tasks> getTasksByType(String type);
/**
* 修改待处理的任务状态
* 设置状态 -->处理中 -->更新数据库信息 -->防止重复操作
*
* @param tasks
* @return
*/
Boolean processTasks(Tasks tasks);
/**
* 处理执行完的任务
*
* @param result
* @param tasks
*/
void endTasks(boolean result, Tasks tasks);
}
package com.service.task.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mapper.TasksMapper;
import com.pojo.Tasks;
import com.service.job.TasksTypeEnum;
import com.service.task.TasksService;
import com.service.task.TasksStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import static java.time.LocalTime.now;
/**
* @author syh
* @date 2023/6/8 14:16
* @details 详情
*/
@Slf4j
@Service
public class TasksServiceImpl extends ServiceImpl<TasksMapper, Tasks> implements TasksService {
/**
* 创建任务
*
* @param tasks
*/
public void createTasks(Tasks tasks) {
}
/**
* 根据类型获取tasks
*
* @param type
* @return
*/
@Override
public List<Tasks> getTasksByType(String type) {
//获取对应类型的任务
LambdaQueryWrapper<Tasks> queryWrapper = new LambdaQueryWrapper<>();
// 业务类型
queryWrapper.eq(Tasks::getBusinessType, Integer.valueOf(type));
queryWrapper.eq(Tasks::getActive, 1);
//获取 0 未处理的 3 处理失败 的任务
queryWrapper.in(Tasks::getStatus, Arrays.asList(0, 3));
//下次处理的时间 <<可控>>
queryWrapper.le(Tasks::getNextDealTime, new Date());
List<Tasks> list = this.list(queryWrapper);
return list;
}
/**
* 修改待处理的任务状态
* 设置状态 -->处理中 -->更新数据库信息 -->防止重复操作
*
* @param tasks
* @return
*/
public Boolean processTasks(Tasks tasks) {
LambdaUpdateWrapper<Tasks> updateWrapper = getUpdateTasksBySystem(tasks);
//此处避免多线程多任务安全问题
updateWrapper.eq(Tasks::getStatus, tasks.getStatus());
// 设置任务为进行中
updateWrapper.set(Tasks::getStatus, TasksStatusEnum.DOING.getCode());
//更新指定的字段
boolean updateBoolean = update(updateWrapper);
return updateBoolean;
}
/**
* 处理执行完的任务
*
* @param result
* @param tasks
*/
public void endTasks(boolean result, Tasks tasks) {
LambdaUpdateWrapper<Tasks> updateWrapper = getUpdateTasksBySystem(tasks);
updateWrapper.eq(Tasks::getStatus, TasksStatusEnum.DOING.getCode());
// 设置任务成功
updateWrapper.set(Tasks::getStatus, TasksStatusEnum.SUCCESS.getCode());
//次数加1
updateWrapper.set(Tasks::getDealCount, tasks.getDealCount() + 1);
//更新指定的字段
boolean updateBoolean = update(updateWrapper);
}
private LambdaUpdateWrapper<Tasks> getUpdateTasksBySystem(Tasks tasks) {
LambdaUpdateWrapper<Tasks> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.set(Tasks::getUpdateUser, "系统");
updateWrapper.set(Tasks::getUpdateTime, new Date());
//处理时间
updateWrapper.set(Tasks::getDealTime, new Date());
updateWrapper.eq(Tasks::getId, tasks.getId());
return updateWrapper;
}
}
5.枚举任务类(TasksTypeEnum,TasksStatusEnum)
package com.service.task;
/**
* @author syh
* @date 2023/6/8 16:14
* @details 类描述
*/
public enum TasksTypeEnum {
/**
*
*/
ONE(1, "StudentService");
private Integer code;
private String desc;
public Integer getCode() {
return code;
}
public String getDesc() {
return desc;
}
TasksTypeEnum(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
public static TasksTypeEnum getTasksTypeEnum(Integer code) {
for (TasksTypeEnum typeEnum : TasksTypeEnum.values()) {
if (code.equals(typeEnum.getCode())) {
return typeEnum;
}
}
return null;
}
}
package com.service.task;
import com.pojo.Tasks;
/**
* @author syh
* @date 2023/6/8 15:10
* @details 类描述
*/
public enum TasksStatusEnum {
UNDO(0, "未处理"),
DOING(1, "处理中"),
SUCCESS(2, "成功"),
FAIL(3, "失败");
private Integer code;
private String desc;
TasksStatusEnum(Integer code, String desc) {
this.code = code;
this.desc = desc;
}
public Integer getCode() {
return code;
}
public String getDesc() {
return desc;
}
}
6.实现dealer接口实现类
package com.service.dealer;
import com.pojo.Tasks;
import com.service.task.TasksTypeEnum;
/**
* @author syh
* @date 2023/6/8 16:07
* @details 处理业务接口
*/
public interface Dealer {
/**
* 具体逻辑实现
* @param tasks
* @return
*/
boolean doDeal(Tasks tasks);
/**
* 接口枚举对应类
* @return
*/
TasksTypeEnum getTasksTypeEnum();
}
package com.service.student;
import com.baomidou.mybatisplus.extension.service.IService;
import com.pojo.Student;
import com.service.dealer.Dealer;
/**
* @author syh
* @date 2023/5/614:14
* @details 详情
*/
public interface StudentService extends IService<Student> , Dealer {
}
package com.service.student.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mapper.StudentMapper;
import com.pojo.Student;
import com.pojo.Tasks;
import com.service.task.TasksTypeEnum;
import com.service.student.StudentService;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
import java.util.UUID;
/**
* @author syh
* @date 2023/5/614:16
* @details 详情
*/
@Service
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {
/**
* job 定时任务实现
* @param tasks
* @return
*/
@Override
public boolean doDeal(Tasks tasks) {
try {
//todo 业务逻辑
System.out.println("双色球,2块钱百万杠杆");
} catch (Exception e) {
return false;
}
return true;
}
/**
* 用于tasksJob
*
* @return
*/
@Override
public TasksTypeEnum getTasksTypeEnum() {
//指定map对应的枚举
return TasksTypeEnum.ONE;
}
}