admin 管理员组文章数量: 1184232
定时器可以按照设定的时间自动重复执行某一个动作。比如用户下订单,现在希望将30分钟内未付款的订单自动取消,就可以写一个定时器,让它每多长时间(如一分钟,两分钟,在这种严格要求数据具有实时性的场景下,这个时间在保证任务能执行完的情况下肯定越小越精确)执行一次,执行的时候,遍历数据库订单表,拿当前时间减去订单创建时间,超过30分钟的删除掉。
一、SpringBoot集成定时器:
先搭建好一个springBoot工程,
<project xmlns="http://maven.apache/POM/4.0.0" xmlns:xsi="http://www.w3/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache/POM/4.0.0 http://maven.apache/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>job</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.1.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
有启动类:
package com.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
//启动定时
@EnableScheduling
public class JobStart {
public static void main(String[] args) {
SpringApplication.run(JobStart.class, args);
}
}
定时Job:
package com.demo.job;
import java.util.Date;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
//或者其他注解都可以,只要让这个类可以被扫描到
@Component
public class JobDemo {
@Scheduled(cron = "0/30 * * * * ?")
public void myTest1(){
System.out.println("job1每30秒执行一次"+new Date());
}
@Scheduled(cron = "0 0/1 * * * ? ")
public void myTest2(){
System.out.println("job2每一分钟执行一次"+new Date());
}
}
之后启动JobStart类启动整个工程,可以看到控制台打印信息如下:
完成。
二、简单应用举例:
例1,现在有一个抢购活动,活动有三种状态:在开始时间(beginTime)前的为未开始状态,在开始时间和结束时间endTime之间的为进行中状态,在结束时间后的为结束状态。创建活动时会设定开始时间、结束时间、状态(均为未开始),现在通过一个job来自动改变活动的状态:
@Component
public class ActivityTask{
@Autowired
private GroupActivityService groupActivityService;
@Scheduled(cron = "0 0/1 * * * ? ")
public void activity() {
try {
//遍历活动表,获取所有未结束的活动
List<Activity> activityList = groupActivityService.getNotEndActivityList();
for(Activity activity:activityList){
Short status = activity.getStatus();
Date beginTime = activity.getBeginTime();
Date endTime = activity.getEndTime();
Date date = new Date();
//待开始的,判断是否开始了
if(status == (short)ActivityStatusEnum.WAIT.getCode()){
//当前时间>开始时间 && 当前时间<结束时间,开始
if(date.after(beginTime) && endTime.after(date)){
activity.setStatus((short)ActivityStatusEnum.START.getCode());
groupActivityService.update(activity);
}
}
//开始的,判断是否结束了
if(status == (short)ActivityStatusEnum.START.getCode()){
//当前时间>结束时间,结束
if(date.after(endTime)){
activity.setStatus((short)ActivityStatusEnum.END.getCode());
groupActivityService.update(activity);
}
}
}
} catch (Throwable t) {
logger.error(t.toString());
}
logger.debug("end job" + new Date());
}
}
例2:定时清理数据,自动转移一年前的历史数据,一天执行一次,一次转移10条(从数据库性能方面考虑一次性全部转移比较慢)
//自动转移一年前的历史数据
@Scheduled(cron = "0 0 3 * * ?")
//@Scheduled(cron = "0 0/1 * * * ? ")
public void tranferToHistory() {
logger.debug("tranferToHistory job begin: " + new Date());
try {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.YEAR, -1);
Date beforeTime = calendar.getTime();
userService.transferToHistory(beforeTime, 10);
} catch (Exception e) {
logger.error("tranferToHistory job error: " + e.getMessage());
}
logger.debug("tranferToHistory job end: " + new Date());
}
userServiceImpl:
@Override
@Transactional
public int transferToHistory(Date beforeTime, Integer size) {
//查询beforeTime之前的size条数据
List<User> userList = userDao.selectHistoryUser(beforeTime,size);
List<Long> userIds = new ArrayList<>();
for(User user:userList){
userIds.add(user.getId());
}
if(!userIds .isEmpty()){
//1、转移用户表数据t_user至t_user_history
notifyDao.insertToUserHistory(userList);
notifyDao.deletesUserForever(userIds);
//2、转移评论t_user_comment中的老数据至t_user_comment_history表
List<UserComment> commentList =
userCommentDao.selectHistoryComment(userIds);
userCommentDao.insertCommentHistory(commentList);
userCommentDao.deletesCommentForever(userIds);
//......转移和用户相关的其他老数据
}
return 1;
}
注:在线cron表达式生成器:http://cron.qqe2/
三、高阶应用:
1、schedule是默认以单线程的情况执行的:
如:
package com.demo.job;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @Description: 单线程举例
*/
@Component
public class ThreadJobDemo {
@Scheduled(cron = "0/30 * * * * ?")
public void myTest1(){
System.out.println("job1每30秒执行一次,线程:"+Thread.currentThread().getId());
}
@Scheduled(cron = "0 0/1 * * * ? ")
public void myTest2(){
System.out.println("job2每一分钟执行一次,线程:"+Thread.currentThread().getId());
}
}
启动类:
package com.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class JobStart {
public static void main(String[] args) {
SpringApplication.run(JobStart.class, args);
}
}
启动后,控制台打印,可以看到线程id都是一样的,说明是在以同一个线程执行:
2、使用 @Async 注解可以实现多线程,启动类上需要加@EnableAsync 注解:这一点从百度上看到的,我实验了结果不正确。
本文标签: schedule SpringBoot
版权声明:本文标题:Schedule(一)SpringBoot整合Schedule 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.roclinux.cn/b/1766278205a3450888.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论