一篇简单的文章带你玩转SpringBoot 之定时任务详解

news2024/12/25 23:43:45

序言

使用SpringBoot创建定时任务非常简单,目前主要有以下三种创建方式:

  • 一、基于注解(@Scheduled)
  • 二、基于接口(SchedulingConfigurer) 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库中读取指定时间来动态执行定时任务,这时候基于接口的定时任务就派上用场了。
  • 三、基于注解设定多线程定时任务

静态:基于注解

基于注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。

创建定时器

使用SpringBoot基于注解来创建定时任务非常简单,只需几行代码便可完成。


代码如下:

@Component
@Configuration      //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling   // 2.开启定时任务
public class SaticScheduleTask {
    //3.添加定时任务
    @Scheduled(cron = "0/5 * * * * ?")
    //或直接指定时间间隔,例如:5秒
    //@Scheduled(fixedRate=5000)
    private void configureTasks() {
        System.err.println("执行静态定时任务时间: " + LocalDateTime.now());
    }
}

 Cron表达式参数分别表示:

  • */5 * * * * ? :每隔5秒执行一次
  • 0 */1 * * * ? :每隔1分钟执行一次
  • 0 0 23 * * ? :每天23点执行一次
  • 0 0 1 * * ? :每天凌晨1点执行一次:
  • 0 0 1 1 * ? :每月1号凌晨1点执行一次
  • 0 0 23 L * ? : 每月最后一天23点执行一次
  • 0 0 1 ? * L :每周星期天凌晨1点实行一次
  • 0 26,29,33 * * * ? : 在26分、29分、33分执行一次
  • 0 0 0,13,18,21 * * ? : 每天的0点、13点、18点、21点都执行一次

Cron表达式由7个部分组成,各部分用空格隔开,Cron表达式的7个部分从左到右代表的含义如下:


其中 是可选的。

              字段名                                  允许的值            允许的特殊字符
0-59,- * /
0-59,- * /
0-23,- * /
1-31,- * ? / L W C
1-12 or JAN-DEC,- * /
1-7 or SUN-SAT,- * ? / L C #
年(可选字段)empty,1970-2099,- * /

符号说明

  • ,:表示列出枚举值值。例如在使用5,20,则意味着在5和20分每分钟触发一次。
  • -:表示范围。例如在使用5-20,表示从5分到20分钟每分钟触发一次。
  • * :表示匹配该域的任意值。假如在域使用*,即表示每分钟都会触发事件。
  • / :表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次。
  • ? :只能用在。它也匹配域的任意值,但实际不会。因为会相互影响。例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?,其中最后一位只能用?,而不能使用,如果使用表示不管星期几都会触发,实际上并不是这样。
  • L : 表示最后,只能出现在,如果在使用5L,意味着在最后的一个星期四触发。
  • W:表示有效工作日(周一到周五),只能出现在域,系统将在离指定日期的最近的有效工作日触发事件。例如:在使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份。
  • #:用于确定每个月第几个星期几,只能出现在。例如在4#2,表示某月的第二个星期三。

 @Scheduled:除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应的毫秒数即可。

 

动态:基于接口

基于接口(SchedulingConfigurer)

导入依赖包pom.xml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
        <version>2.0.4.RELEASE</version>
    </parent>

    <dependencies>
        <dependency><!--添加Web依赖 -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency><!--添加MySql依赖 -->
             <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency><!--添加Mybatis依赖 配置mybatis的一些初始化的东西-->
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency><!-- 添加mybatis依赖 -->
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

添加数据库记录:

DROP DATABASE IF EXISTS `socks`;
CREATE DATABASE `socks`;
USE `SOCKS`;
DROP TABLE IF EXISTS `cron`;
CREATE TABLE `cron`  (
  `cron_id` varchar(30) NOT NULL PRIMARY KEY,
  `cron` varchar(30) NOT NULL  
);
INSERT INTO `cron` VALUES ('1', '0/5 * * * * ?');

然后在项目中的application.properties 文件中
添加数据源:

server.port = 8888

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url= jdbc:mysql://127.0.0.1:3306/ordersystem?useUnicode=true&characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root

创建定时器

数据库准备好数据之后,我们编写定时任务,注意这里添加的是TriggerTask,目的是循环读取我们在数据库设置好的执行周期,以及执行相关定时任务的内容。

@Component
@Configuration      //1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling   // 2.开启定时任务
public class DynamicScheduleTask implements SchedulingConfigurer {

    @Mapper
    public interface CronMapper {
        @Select("select cron from cron limit 1")
        public String getCron();
    }

    @Autowired      //注入mapper
    @SuppressWarnings("all")
    CronMapper cronMapper;

    /**
     * 执行定时任务.
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

        taskRegistrar.addTriggerTask(
                //1.添加任务内容(Runnable)
                () -> System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime()),
                //2.设置执行周期(Trigger)
                triggerContext -> {
                    //2.1 从数据库获取执行周期
                    String cron = cronMapper.getCron();
                    //2.2 合法性校验.
                    if (StringUtils.isEmpty(cron)) {
                        // Omitted Code ..
                    }
                    //2.3 返回执行周期(Date)
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                }
        );
    }

}

 注意:如果在数据库修改时格式出现错误,则定时任务会停止,即使重新修改正确;此时只能重新启动项目才能恢复。

多线程

基于注解设定多线程定时任务

创建多线程定时任务

例子:我下订单后,要求订单在30分钟内如果未支付则自动取消该订单

package com.shijiu.component;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.shijiu.dao.mapper.ShopOrderMapper;
import com.shijiu.pojo.ShopOrder;
import com.shijiu.service.ShopOrderService;
import com.shijiu.service.impl.ShopOrderServiceImpl;
import io.swagger.annotations.ApiOperation;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author 
 * @Date Created in  2023/4/27 9:52
 * @DESCRIPTION:
 * @Version V1.0
 */

//@Component注解用于对那些比较中立的类进行注释;
//相对与在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释
@Component
// 1.开启定时任务
@EnableScheduling
/**
  2.开启多线程(定时任务检查删除订单)
 */
@EnableAsync
@SuppressWarnings("all")
public class MultithreadScheduleTask {
   @Resource
   private ShopOrderMapper shopOrderMapper;

   @Async
   @Scheduled(fixedDelay = 60000)
   @ApiOperation("/* 间隔1分钟定时检查数据库 */")
   public void first() throws InterruptedException {
      LambdaQueryWrapper<ShopOrder> wrapper = new LambdaQueryWrapper<>();
      wrapper.eq(ShopOrder::getStatus,"0").eq(ShopOrder::getIsDeleted,"0");
      //拿到所有的订单
      List<ShopOrder> shopOrderList = shopOrderMapper.selectList(wrapper);
      List<ShopOrder> filteredOrders = shopOrderList.stream()
              .filter(order -> Math.ceil(DateUtil.betweenMs(order.getCreateTime(), order.getOverTime())) / 60000.0  > 30) // 保留订单结束时间与创建时间间隔超过30分钟的订单
              .collect(Collectors.toList()); // 将满足条件的订单收集到一个新的集合中
      //double result = Math.ceil(DateUtil.betweenMs("2023-04-27 10:05:03", "2023-04-27 10:07:02") / 60000.0);
       // 对筛选出来的订单执行xxx操作
      System.out.println(filteredOrders);
      filteredOrders.forEach(order -> {
         // 对订单执行xxx操作,例如:
         String orderId = order.getId();
         ShopOrder shopOrder = new ShopOrder();
         shopOrder.setId(shopOrderId);
         shopOrder.setIsDeleted("1");
         shopOrderMapper.updateById(shopOrder);
      });
   }
}

打印结果:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/466699.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux网络编程TCP连接的建立和终止

文章目录 前言一、TCP的三路握手二、TCP连接终止总结 前言 本篇文章将讲解TCP的连接的建立和终止&#xff0c;主要就是讲解TCP的三路握手和TCP连接断开内部发生的一些机制和事件。 一、TCP的三路握手 TCP三路握手所交换的三个分节&#xff1a; (1)服务器必须准备好接受外来…

C++题解之对顶堆:中位数

中位数 题目链接&#xff1a;洛谷P1168 中位数 题目描述 给定一个长度为 N N N 的非负整数序列 A A A&#xff0c;对于前奇数项求中位数。 输入格式 第一行一个正整数 N N N。 第二行 N N N 个正整数 A 1 … N A_{1\dots N} A1…N​。 输出格式 共 ⌊ N 1 2 ⌋ …

【是C++,不是C艹】 省缺参数 | 函数重载 | 内联函数

&#x1f49e;&#x1f49e;欢迎来到 Claffic 的博客 &#x1f49e;&#x1f49e; &#x1f449; 专栏&#xff1a;《是C&#xff0c;不是C艹》&#x1f448; 前言&#xff1a; 上期&#xff0c;我带大家给C打了招呼&#xff0c;捎带着认识了命名空间和输入输出&#xff0c;那…

LeetCode——链表简单题题解

83. 删除排序链表中的重复元素 题目描述 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 输入&#xff1a;head [1,1,2] 输出&#xff1a;[1,2] 解题思路&#xff1a;用一个指向节点类型的指针保…

Vscode配置C/C++开发环境

下载Vscode进行安装。 下载MinGW-W64 GCC最新版本&#xff0c; 选择x86_64-win32-seh进行下载。解压放入自定义目录&#xff08;英文路径&#xff09;后&#xff0c;添加$:\mingw64\bin到系统Path环境变量。安装C/C插件。 在.c后缀文件中按Ctr Shift P&#xff0c;选择C/C …

Windows系统文件被faust勒索病毒加密勒索病毒解密恢复,电脑中病毒了怎么修复?

恶意软件的攻击已经让电脑用户变得更加谨慎了。在最近的一波攻击中&#xff0c;faust勒索病毒已经对使用Windows系统的计算机造成了广泛的破坏。该病毒利用加密技术锁定用户的文件&#xff0c;只有在支付一定数额的赎金后才会解锁这些文件。如果你的计算机中也受到了这种勒索病…

MaxScript编写bone转换biped工具

一、制作转换工具的缘由 大家好&#xff0c;我是阿赵。我经常从各种渠道得到了一些角色模型&#xff0c;这些模型得到之后&#xff0c;会发现是带有蒙皮和骨骼&#xff0c;甚至带有动作的。   不过这些资源很多都是从游戏截取出来的&#xff0c;导入到3DsMax之后&#xff0c;…

信息安全复习十:Web与电子商务安全

一、章节梗概 1.信息安全的学科内容 2.Web和电子商务安全问题提出 3.安全套接字协议SSL与传输层安全协议TLS 4.安全电子交易(SET)简要介绍 复习&#xff1a; 密码学内容&#xff1a;对称密钥密码、公开密钥密码、报文鉴别 PKI&#xff1a;数字签名、数字证书、信任关系 身份认…

MES管理系统助力企业数字化与实体经济实现“数实融合“

中国企业评估协会日前公布了2022年度“中国新经济500强”的名单。在这些企业中&#xff0c;先进制造业企业的比例超过了半数&#xff0c;尤其是互联网与现代信息技术服务业、新能源产业、新型生活性服务业等&#xff0c;在这些行业中占据了重要地位。由此可以看出&#xff0c;绿…

C/C++每日一练(20230427) 二叉树专场(5)

目录 1. 从中序与后序遍历序列构造二叉树 &#x1f31f;&#x1f31f; 2. 从先序与中序遍历序列构造二叉树 &#x1f31f;&#x1f31f; 3. 二叉树展开为链表 &#x1f31f;&#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每…

微信小程序php+python+nodejs+vue 高校工资管理系统

在线公益知识练习及测试系统是随着计算机技术和互联网技术的发展而产生的一种的新的练习及测试模式&#xff0c;与传统的纸质化练习及测试不同&#xff0c;在线系统提高了练习或测试的效率&#xff0c;减少了纸张的浪费&#xff0c;减轻了教师的评卷压力&#xff0c;同时也为参…

易观千帆 | 金融机构如何保证用户体验长期可持续?

易观&#xff1a;用户体验正逐渐成为金融机构的命脉。 数字经济时代的到来&#xff0c;金融机构面临着来自内部和外部的双重压力。一方面&#xff0c;互联网金融企业凭借强大的技术能力以及人才优势&#xff0c;通过互联网运营的模式迅速响应客户需求&#xff0c;吸引了大量用户…

自定义Feign日志

文章目录 开篇定位Feign是怎么打印日志的&#xff1f;自定义FeignLogger实现 开篇 在上一篇Feign打印日志文章中&#xff0c;已经成功打印了FeignClient请求服务的日志信息&#xff0c;但是默认打印的日志太过零散&#xff0c;不是我们想要的。怎么能自定义日志打印的格式和内…

系统分析师《企业信息化战略与实施》高频知识点二

企业信息化战略与实施---系统建模 组织结构是一个企业内部部门的划分以及相互之间的关系&#xff0c;每个企业都有自己的组织结构图&#xff0c;它将企业分成若干部分&#xff0c;标明行政隶属关系。组织结构图是一种树结构&#xff0c;树的分支是根据上下级和行政隶属关系绘制…

二叉树 + 技巧

题目难度备注2471. 逐层排序二叉树所需的最少操作数目1635BFS 置换环 离散化2641. 二叉树的堂兄弟节点 II1677BFS 文章目录 周赛二叉树问题[2471. 逐层排序二叉树所需的最少操作数目](https://leetcode.cn/problems/minimum-number-of-operations-to-sort-a-binary-tree-by-l…

【AI绘画】云服务器部署stable-diffusion-webui保姆级教程

1.背景 之前给大家写过Mac苹果笔记本上部署stable-diffusion-webui的教程&#xff0c;知乎链接&#xff1a; 【奶奶看了也不会】AI绘画 Mac安装stable-diffusion-webui绘制AI妹子保姆级教程 但是安装过程就花了一天的时间&#xff0c;各种问题处理起来真是苦不堪言。。。而且…

如何解决生产缺料问题?

对于一个生产型企业来说&#xff0c;生产缺料是管理中的疑难问题之一。 生产缺料导致的最直接的危害就有两个&#xff1a; 第一就是不能准时交货&#xff0c;降低企业信用&#xff0c;情况严重可能导致根据合同赔款&#xff0c;甚至丢失客户。 第二个危害就是增加了生产成本…

部署LVS-DR 集群及实验

一、LVS-DR工作原理 LVS-DR&#xff08;Linux Virtual Server Director Server&#xff09;工作模式&#xff0c;是生产环境中最常用的一种工作模式。 #①LVS-DR 模式&#xff0c;Director Server 作为群集的访问入口&#xff0c;不作为网关使用&#xff1b; #②节点 Directo…

ueditor富文本编辑器上传木马图片或木马文件漏洞

漏洞分析&#xff1a; ueditor插件目录一般都自带index.html文件&#xff08;完整demo文件&#xff09;&#xff0c;这个文件原来是用来测试插件功能的&#xff0c;但粗心的程序员们&#xff0c;开发好项目后&#xff0c;都忘记删除这个demo文件了&#xff0c;导致黑客可以很轻…

微服务不是本地部署的最佳选择,不妨试试模块化单体

微服务仅适用于成熟产品 关于从头开始使用微服务&#xff0c;马丁・福勒&#xff08;Martin Fowler&#xff09;总结道&#xff1a; 1. 几乎所有成功的微服务都是从一个过于庞大而不得不拆分的单体应用开始的。 2. 几乎所有从头开始以微服务构建的系统&#xff0c;最后都会因…