之前转载过一篇使用Timer定时器完成定时任务,这次我们使用@Scheduled注解来实现定时更新数据库数据
在Spring Boot项目中,由于使用注解替代了大量的配置文件,所以直接使用该注解即可。
在MVC框架下,则需要配置一些数据。
在spring的配置xml文件中添加以下内容
xmlns中加入
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation中加入
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd"
Spring扫描注解的配置
<task:annotation-driven/>
<context:component-scan
base-package="com.test.utils" />
如下图所示:
此时就完成了配置可以创建我们的定时任务了
创建一个类用来运行定时任务
@Component
public class TimeTask {
@Autowired
WorkorderService workorderService;
@Autowired
WorkOrderDao workOrderDao;
private static final Logger log = Logger.getLogger(TimeTask.class);
//每隔一分钟 0 */1 * * * ?
//每个月1日凌晨2点15分30秒 30 15 2 1 * ?
//定时任务每个月1日0点定时清空任务状态和发生时间和截至时间 0 0 0 1 * ?
@Scheduled(cron = "30 15 2 1 * ?")
public void updateOnTime() {
List<WorkOrderSelective> workOrderList = workOrderDao.queryAll();
if (workOrderList.size()!=0){
workorderService.updateOnTime(workOrderList);
// System.out.println("每个月定时重置保养和点检工单");
log.debug("每个月定时重置保养和点检工单");
}
}
}
这边类的上面使用了@component注解 作用就是把普通pojo实例化到spring容器中,相当于配置文件中的 <bean id="" class=""/>
泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller、@Services等的时候),我们就可以使用@Component来标注这个类。
cron表达式语法
[秒] [分] [小时] [日] [月] [周] [年]
序号 | 说明 | 必填 | 允许填写的值 | 允许的通配符 |
---|---|---|---|---|
1 | 秒 | 是 | 0-59 | , - * / |
2 | 分 | 是 | 0-59 | , - * / |
3 | 时 | 是 | 0-23 | , - * / |
4 | 日 | 是 | 1-31 | , - * ? / L W |
5 | 月 | 是 | 1-12 / JAN-DEC | , - * / |
6 | 周 | 是 | 1-7 or SUN-SAT | , - * ? / L # |
7 | 年 | 否 | 1970-2099 | , - * / |
通配符说明:
*
表示所有值。 例如:在分的字段上设置 *,表示每一分钟都会触发。?
表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作,但不关心是周几,所以需要周位置的那个字段设置为”?” 具体设置为 0 0 0 10 * ?-
表示区间。例如 在小时上设置 “10-12”,表示 10,11,12点都会触发。,
表示指定多个值,例如在周字段上设置 “MON,WED,FRI” 表示周一,周三和周五触发/
用于递增触发。如在秒上面设置”5/15” 表示从5秒开始,每增15秒触发(5,20,35,50)。 在日字段上设置’1/3’所示每月1号开始,每隔三天触发一次。L
表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年[leap]), 在周字段上表示星期六,相当于”7”或”SAT”。如果在”L”前加上数字,则表示该数据的最后一个。例如在周字段上设置”6L”这样的格式,则表示“本月最后一个星期五”W
表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上置”15W”,表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 “1W”,它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,”W”前只能设置具体的数字,不允许区间”-“)。#
序号(表示每月的第几个周几),例如在周字段上设置”6#3”表示在每月的第三个周六.注意如果指定”#5”,正好第五周没有周六,则不会触发该配置(用在母亲节和父亲节再合适不过了) ;小提示:’L’和 ‘W’可以一组合使用。如果在日字段上设置”LW”,则表示在本月的最后一个工作日触发;周字段的设置,若使用英文字母是不区分大小写的,即MON与mon相同。
示例
每隔5秒执行一次:*/5 * * * * ?
每隔1分钟执行一次:0 */1 * * * ?
每天23点执行一次:0 0 23 * * ?
每天凌晨1点执行一次:0 0 1 * * ?
每月1号凌晨1点执行一次:0 0 1 1 * ?
每月最后一天23点执行一次:0 0 23 L * ?
每周星期六凌晨1点实行一次:0 0 1 ? * L
在26分、29分、33分执行一次:0 26,29,33 * * * ?
每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?
我这边的业务是每个月定时重置工单数据,即完成状态和截止时间和完成时间
查询出所有需要重置的数据存入list中,再将这个list在mybatis中使用<foreach>标签循环遍历
dao层
int updateOnTime(List<WorkOrderSelective> workOrderList);
mybatis中sql语句
查询限定时间为下个月0点也就是这个月末的工单数据
<select id="queryMainOrCheck" parameterType="workOrderExtModel" resultType="workOrderExtModel">
select * from work_order
<trim prefix="where" prefixOverrides="and">
endTime = (select date_add(curdate()-day(curdate())+1,interval 1 month ))
<if test="null!=orderStatus">
and orderStatus = #{orderStatus}
</if>
<if test="null!=orderTypeId">
and orderTypeId = #{orderTypeId}
</if>
</trim>
<if test="pageSize != null">
limit #{offset},#{pageSize}
</if>
</select>
MySQL查询下个月1号
select date_add(curdate()-day(curdate())+1,interval 1 month )
MySQL查询这个月1号
select DATE_ADD(curdate(),interval -day(curdate())+1 day)
根据传入的list工单数据,遍历更新重置每一条工单
<update id="updateOnTime" parameterType="list" >
update work_order
set
happenTime = null,
endTime = (select date_add(curdate()-day(curdate())+1,interval 1 month )),
orderStatus = 3
where orderId in
<foreach collection="list" item="item" open="(" separator="," close=")" >
#{item.orderId}
</foreach>
</update>
至此,就可以实现定时更新数据库信息了