zoukankan      html  css  js  c++  java
  • spring boot+Quartz+数据库存储

    SpingBoot+Quartz+数据库存储

    1、Spring整合Quartz

    2、读取数据库中表达式启动定时任务1(每5s执行)

    3、更改定时任务状态(启用/禁用),定时任务1停止

    4、读取数据库中表达式启动定时任务2(每5s执行),在对应作业类中打印定时任务2携带的参数

    5、读取数据库中表达式启动定时任务3(每5s执行改成每20s执行),更改数据库定时任务表达式,定时任务3对应执行策略相应发生改变。

    Spring整合Quartz

    a、quartz调度框架是有内置表的

    进入quartz的官网http://www.quartz-scheduler.org/,点击Downloads

       下载后在目录docsdbTables下有常用数据库创建quartz表的脚本,例如:“tables_mysql.sql

     

    table_mysql.sql

       table_mysql_innodb.sql

       上述两者所有的数据库引擎不一样

     

    导入pom依赖

    1   <dependency>
    2     <groupId>com.alibaba</groupId>
    3     <artifactId>druid-spring-boot-starter</artifactId>
    4     <version>1.1.10</version>
    5    </dependency>

    c、在项目中添加quartz.properties文件(这样就不会加载自带的properties文件)
    此文件的内容主要分为:scheduler,ThreadPool,JobStore,plugin,Datasources等部分,
    覆盖properties文件的目的是覆盖默认的数据源,更换为druid的数据配置
    d、自定义MyJobFactory,解决spring不能在quartz中注入bean的问题
    e、创建调度器schedule,交给spring进行管理
    f、创建自定义任务
    g、更新quartz中的任务
    自定义任务表与quartz内置表的区分

    要搞清楚一个问题:从数据库读取任务信息动态生成定时任务,和把quartz持久化到数据库是没有关系的。

    前者是我们自己定义的业务表,而后者是quartz使用自己的表来存储信息。

    持久化到数据库后,就算服务器重启或是多个quartz节点也没关系,因为他们共享数据库中的任务信息。

    创建项目

    自定义业务表

     1 -- 注意:job_name存放的任务类的全路径,在quartz中通过jobName和jobGroup来确定trigger的唯一性,所以这两列为联合唯一索引
     2 create table t_schedule_trigger
     3 (
     4   id int primary key auto_increment,                                -- ID
     5   cron varchar(200) not null,                                       -- 时间表达式
     6   status char(1) not null,                                          -- 使用状态 0:禁用   1:启用
     7   job_name varchar(200) not null,                                   -- 任务名称
     8   job_group varchar(200) not null,                                  -- 任务分组  
     9   unique index(job_name,job_group)
    10 );
    11 
    12 -- 额外添加到任务中的参数
    13 create table t_schedule_trigger_param
    14 (
    15   param_id int primary key auto_increment,                                -- ID
    16   name varchar(200) not null,                                             -- 参数名
    17   value varchar(512),                                                     -- 参数值
    18  
    19   schedule_trigger_id int not null,                                       -- 外键:引用t_schedule_trigger(id)
    20   foreign key(schedule_trigger_id) references t_schedule_trigger(id)
    21 );

    DruidConnectionProvider

      1 package com.yuan.quartz02.utils;
      2 
      3 import com.alibaba.druid.pool.DruidDataSource;
      4 import org.quartz.SchedulerException;
      5 import org.quartz.utils.ConnectionProvider;
      6 
      7 import java.sql.Connection;
      8 import java.sql.SQLException;
      9 
     10 /*
     11 #============================================================================
     12 # JDBC
     13 #============================================================================
     14 org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
     15 org.quartz.jobStore.useProperties:false
     16 org.quartz.jobStore.dataSource:qzDS
     17 #org.quartz.dataSource.qzDS.connectionProvider.class:org.quartz.utils.PoolingConnectionProvider
     18 org.quartz.dataSource.qzDS.connectionProvider.class:com.zking.q03.quartz.DruidConnectionProvider
     19 org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver
     20 org.quartz.dataSource.qzDS.URL:jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8
     21 org.quartz.dataSource.qzDS.user:root
     22 org.quartz.dataSource.qzDS.password:root
     23 org.quartz.dataSource.qzDS.maxConnections:30
     24 org.quartz.dataSource.qzDS.validationQuery: select 0
     25 */
     26 
     27 /**
     28  * [Druid连接池的Quartz扩展类]
     29  *
     30  * @ProjectName: []
     31  * @Author: [xuguang]
     32  * @CreateDate: [2015/11/10 17:58]
     33  * @Update: [说明本次修改内容] BY[xuguang][2015/11/10]
     34  * @Version: [v1.0]
     35  */
     36 public class DruidConnectionProvider implements ConnectionProvider {
     37 
     38      /*
     39      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     40      *
     41      * 常量配置,与quartz.properties文件的key保持一致(去掉前缀),同时提供set方法,Quartz框架自动注入值。
     42      *
     43      * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     44      */
     45 
     46     //JDBC驱动
     47     public String driver;
     48     //JDBC连接串
     49     public String URL;
     50     //数据库用户名
     51     public String user;
     52     //数据库用户密码
     53     public String password;
     54     //数据库最大连接数
     55     public int maxConnection;
     56     //数据库SQL查询每次连接返回执行到连接池,以确保它仍然是有效的。
     57     public String validationQuery;
     58 
     59     private boolean validateOnCheckout;
     60 
     61     private int idleConnectionValidationSeconds;
     62 
     63     public String maxCachedStatementsPerConnection;
     64 
     65     private String discardIdleConnectionsSeconds;
     66 
     67     public static final int DEFAULT_DB_MAX_CONNECTIONS = 10;
     68 
     69     public static final int DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION = 120;
     70 
     71     //Druid连接池
     72     private DruidDataSource datasource;
     73 
     74     /*
     75     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     76     *
     77     * 接口实现
     78     *
     79     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     80     */
     81     public Connection getConnection() throws SQLException {
     82         return datasource.getConnection();
     83     }
     84 
     85     public void shutdown() throws SQLException {
     86         datasource.close();
     87     }
     88     public void initialize() throws SQLException{
     89         if (this.URL == null) {
     90             throw new SQLException("DBPool could not be created: DB URL cannot be null");
     91         }
     92 
     93         if (this.driver == null) {
     94             throw new SQLException("DBPool driver could not be created: DB driver class name cannot be null!");
     95         }
     96 
     97         if (this.maxConnection < 0) {
     98             throw new SQLException("DBPool maxConnectins could not be created: Max connections must be greater than zero!");
     99         }
    100 
    101         datasource = new DruidDataSource();
    102         try{
    103             datasource.setDriverClassName(this.driver);
    104         } catch (Exception e) {
    105             try {
    106                 throw new SchedulerException("Problem setting driver class name on datasource: " + e.getMessage(), e);
    107             } catch (SchedulerException e1) {
    108             }
    109         }
    110 
    111         datasource.setUrl(this.URL);
    112         datasource.setUsername(this.user);
    113         datasource.setPassword(this.password);
    114         datasource.setMaxActive(this.maxConnection);
    115         datasource.setMinIdle(1);
    116         datasource.setMaxWait(0);
    117         datasource.setMaxPoolPreparedStatementPerConnectionSize(this.DEFAULT_DB_MAX_CACHED_STATEMENTS_PER_CONNECTION);
    118 
    119         if (this.validationQuery != null) {
    120             datasource.setValidationQuery(this.validationQuery);
    121             if(!this.validateOnCheckout)
    122                 datasource.setTestOnReturn(true);
    123             else
    124                 datasource.setTestOnBorrow(true);
    125             datasource.setValidationQueryTimeout(this.idleConnectionValidationSeconds);
    126         }
    127     }
    128 
    129     /*
    130     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    131     *
    132     * 提供get set方法
    133     *
    134     * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    135     */
    136     public String getDriver() {
    137         return driver;
    138     }
    139 
    140     public void setDriver(String driver) {
    141         this.driver = driver;
    142     }
    143 
    144     public String getURL() {
    145         return URL;
    146     }
    147 
    148     public void setURL(String URL) {
    149         this.URL = URL;
    150     }
    151 
    152     public String getUser() {
    153         return user;
    154     }
    155 
    156     public void setUser(String user) {
    157         this.user = user;
    158     }
    159 
    160     public String getPassword() {
    161         return password;
    162     }
    163 
    164     public void setPassword(String password) {
    165         this.password = password;
    166     }
    167 
    168     public int getMaxConnection() {
    169         return maxConnection;
    170     }
    171 
    172     public void setMaxConnection(int maxConnection) {
    173         this.maxConnection = maxConnection;
    174     }
    175 
    176     public String getValidationQuery() {
    177         return validationQuery;
    178     }
    179 
    180     public void setValidationQuery(String validationQuery) {
    181         this.validationQuery = validationQuery;
    182     }
    183 
    184     public boolean isValidateOnCheckout() {
    185         return validateOnCheckout;
    186     }
    187 
    188     public void setValidateOnCheckout(boolean validateOnCheckout) {
    189         this.validateOnCheckout = validateOnCheckout;
    190     }
    191 
    192     public int getIdleConnectionValidationSeconds() {
    193         return idleConnectionValidationSeconds;
    194     }
    195 
    196     public void setIdleConnectionValidationSeconds(int idleConnectionValidationSeconds) {
    197         this.idleConnectionValidationSeconds = idleConnectionValidationSeconds;
    198     }
    199 
    200     public DruidDataSource getDatasource() {
    201         return datasource;
    202     }
    203 
    204     public void setDatasource(DruidDataSource datasource) {
    205         this.datasource = datasource;
    206     }
    207 }

    quartz.properties

     1 #
     2 #============================================================================
     3 # Configure Main Scheduler Properties 调度器属性
     4 #============================================================================
     5 org.quartz.scheduler.instanceName: DefaultQuartzScheduler
     6 org.quartz.scheduler.instanceId = AUTO
     7 org.quartz.scheduler.rmi.export: false
     8 org.quartz.scheduler.rmi.proxy: false
     9 org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
    10 org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
    11 org.quartz.threadPool.threadCount= 10
    12 org.quartz.threadPool.threadPriority: 5
    13 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
    14 org.quartz.jobStore.misfireThreshold: 60000
    15 #============================================================================
    16 # Configure JobStore
    17 #============================================================================
    18 #存储方式使用JobStoreTX,也就是数据库
    19 org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
    20 org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
    21 #使用自己的配置文件
    22 org.quartz.jobStore.useProperties:true
    23 #数据库中quartz表的表名前缀
    24 org.quartz.jobStore.tablePrefix:qrtz_
    25 org.quartz.jobStore.dataSource:qzDS
    26 #是否使用集群(如果项目只部署到 一台服务器,就不用了)
    27 org.quartz.jobStore.isClustered = true
    28 #============================================================================
    29 # Configure Datasources
    30 #============================================================================
    31 #配置数据库源(org.quartz.dataSource.qzDS.maxConnections: c3p0配置的是有s的,druid数据源没有s)
    32 org.quartz.dataSource.qzDS.connectionProvider.class:com.yuan.quartz02.utils.DruidConnectionProvider
    33 org.quartz.dataSource.qzDS.driver: com.mysql.jdbc.Driver
    34 org.quartz.dataSource.qzDS.URL: jdbc:mysql://localhost:3306/j2ee?useUnicode=true&characterEncoding=utf8
    35 org.quartz.dataSource.qzDS.user: root
    36 org.quartz.dataSource.qzDS.password: 12345
    37 org.quartz.dataSource.qzDS.maxConnection: 10

    MyJobFactory

     1 package com.yuan.quartz02.utils;
     2 
     3 import lombok.extern.slf4j.Slf4j;
     4 import org.quartz.spi.TriggerFiredBundle;
     5 import org.springframework.beans.factory.annotation.Autowired;
     6 import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
     7 import org.springframework.scheduling.quartz.AdaptableJobFactory;
     8 import org.springframework.stereotype.Component;
     9 
    10 @Component
    11 @Slf4j
    12 public class MyJobFactory extends AdaptableJobFactory {
    13 
    14     //这个对象Spring会帮我们自动注入进来
    15     @Autowired
    16     private AutowireCapableBeanFactory autowireCapableBeanFactory;
    17 
    18     //重写创建Job任务的实例方法
    19     @Override
    20     protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
    21         Object jobInstance = super.createJobInstance(bundle);
    22         //通过以下方式,解决Job任务无法使用Spring中的Bean问题
    23         autowireCapableBeanFactory.autowireBean(jobInstance);
    24         return super.createJobInstance(bundle);
    25     }
    26 }

    QuartzConfiguration.java(quartz调度框架与spring框架整合的配置类,主要是要将org.quartz.Scheduler交给spring进行管理)

     1 package com.yuan.quartz02.config;
     2 
     3 import com.yuan.quartz02.utils.MyJobFactory;
     4 import org.quartz.Scheduler;
     5 import org.springframework.beans.factory.annotation.Autowired;
     6 import org.springframework.beans.factory.config.PropertiesFactoryBean;
     7 import org.springframework.context.annotation.Bean;
     8 import org.springframework.context.annotation.Configuration;
     9 import org.springframework.core.io.ClassPathResource;
    10 import org.springframework.scheduling.quartz.SchedulerFactoryBean;
    11 
    12 import java.io.IOException;
    13 import java.util.Properties;
    14 
    15 @Configuration
    16 public class QuartzConfiguration {
    17 
    18     @Autowired
    19     private MyJobFactory myJobFactory;
    20 
    21     //创建调度器工厂
    22     @Bean
    23         public SchedulerFactoryBean schedulerFactoryBean(){
    24             //1.创建SchedulerFactoryBean
    25             //2.加载自定义的quartz.properties配置文件
    26             //3.设置MyJobFactory
    27 
    28             SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
    29             try {
    30                 factoryBean.setQuartzProperties(quartzProperties());
    31                 factoryBean.setJobFactory(myJobFactory);
    32                 return factoryBean;
    33             } catch (IOException e) {
    34                 throw new RuntimeException(e);
    35             }
    36     }
    37 
    38     @Bean
    39     public Properties quartzProperties() throws IOException {
    40         PropertiesFactoryBean propertiesFactoryBean=new PropertiesFactoryBean();
    41         propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
    42         propertiesFactoryBean.afterPropertiesSet();
    43         return propertiesFactoryBean.getObject();
    44     }
    45 
    46     @Bean(name="scheduler")
    47     public Scheduler scheduler(){
    48         return schedulerFactoryBean().getScheduler();
    49     }
    50 }

    案例中需要观察表数据变化的表

     1 -- 自定义的业务表
     2 SELECT * FROM t_schedule_trigger;
     3 SELECT * FROM t_schedule_trigger_param;
     4 
     5 -- quartz调度框架自带的表
     6 SELECT * FROM qrtz_scheduler_state;
     7 SELECT * FROM qrtz_cron_triggers;
     8 SELECT * FROM qrtz_simple_triggers
     9 SELECT * FROM qrtz_triggers;
    10 SELECT * FROM qrtz_job_details;

    项目目录结构

    导入pom依赖

      1 <?xml version="1.0" encoding="UTF-8"?>
      2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      4     <modelVersion>4.0.0</modelVersion>
      5     <parent>
      6         <groupId>org.springframework.boot</groupId>
      7         <artifactId>spring-boot-starter-parent</artifactId>
      8         <version>2.2.1.RELEASE</version>
      9         <relativePath/> <!-- lookup parent from repository -->
     10     </parent>
     11     <groupId>com.yuan</groupId>
     12     <artifactId>quartz02</artifactId>
     13     <version>0.0.1-SNAPSHOT</version>
     14     <name>quartz02</name>
     15     <description>Demo project for Spring Boot</description>
     16 
     17     <properties>
     18         <java.version>1.8</java.version>
     19         <mysql.version>5.1.44</mysql.version>
     20     </properties>
     21 
     22     <dependencies>
     23         <dependency>
     24             <groupId>org.springframework.boot</groupId>
     25             <artifactId>spring-boot-starter-jdbc</artifactId>
     26         </dependency>
     27         <dependency>
     28             <groupId>org.springframework.boot</groupId>
     29             <artifactId>spring-boot-starter-quartz</artifactId>
     30         </dependency>
     31         <dependency>
     32             <groupId>org.springframework.boot</groupId>
     33             <artifactId>spring-boot-starter-thymeleaf</artifactId>
     34         </dependency>
     35         <dependency>
     36             <groupId>org.springframework.boot</groupId>
     37             <artifactId>spring-boot-starter-web</artifactId>
     38         </dependency>
     39         <dependency>
     40             <groupId>org.mybatis.spring.boot</groupId>
     41             <artifactId>mybatis-spring-boot-starter</artifactId>
     42             <version>2.1.1</version>
     43         </dependency>
     44 
     45         <dependency>
     46             <groupId>mysql</groupId>
     47             <artifactId>mysql-connector-java</artifactId>
     48             <version>${mysql.version}</version>
     49             <scope>runtime</scope>
     50         </dependency>
     51         <dependency>
     52             <groupId>org.projectlombok</groupId>
     53             <artifactId>lombok</artifactId>
     54             <optional>true</optional>
     55         </dependency>
     56         <dependency>
     57             <groupId>org.springframework.boot</groupId>
     58             <artifactId>spring-boot-starter-test</artifactId>
     59             <scope>test</scope>
     60             <exclusions>
     61                 <exclusion>
     62                     <groupId>org.junit.vintage</groupId>
     63                     <artifactId>junit-vintage-engine</artifactId>
     64                 </exclusion>
     65             </exclusions>
     66         </dependency>
     67 
     68         <dependency>
     69             <groupId>com.alibaba</groupId>
     70             <artifactId>druid-spring-boot-starter</artifactId>
     71             <version>1.1.10</version>
     72         </dependency>
     73         <dependency>
     74             <groupId>org.quartz-scheduler</groupId>
     75             <artifactId>quartz-jobs</artifactId>
     76             <version>2.2.1</version>
     77         </dependency>
     78 
     79     </dependencies>
     80 
     81     <build>
     82 
     83         <resources>
     84             <resource>
     85                 <directory>src/main/resources</directory>
     86             </resource>
     87             <!--解决mybatis-generator-maven-plugin运行时没有将XxxMapper.xml文件放入target文件夹的问题-->
     88             <resource>
     89                 <directory>src/main/java</directory>
     90                 <includes>
     91                     <include>**/*.xml</include>
     92                 </includes>
     93             </resource>
     94             <!--解决mybatis-generator-maven-plugin运行时没有将jdbc.properites文件放入target文件夹的问题-->
     95             <resource>
     96                 <directory>src/main/resources</directory>
     97                 <includes>
     98                     <include>*.properties</include>
     99                     <include>*.xml</include>
    100                     <include>*.yml</include>
    101                 </includes>
    102             </resource>
    103         </resources>
    104 
    105 
    106         <plugins>
    107             <plugin>
    108                 <groupId>org.mybatis.generator</groupId>
    109                 <artifactId>mybatis-generator-maven-plugin</artifactId>
    110                 <version>1.3.2</version>
    111                 <dependencies>
    112                     <!--使用Mybatis-generator插件不能使用太高版本的mysql驱动 -->
    113                     <dependency>
    114                         <groupId>mysql</groupId>
    115                         <artifactId>mysql-connector-java</artifactId>
    116                         <version>${mysql.version}</version>
    117                     </dependency>
    118                 </dependencies>
    119                 <configuration>
    120                     <overwrite>true</overwrite>
    121                 </configuration>
    122             </plugin>
    123 
    124             <plugin>
    125                 <groupId>org.springframework.boot</groupId>
    126                 <artifactId>spring-boot-maven-plugin</artifactId>
    127             </plugin>
    128         </plugins>
    129     </build>
    130 
    131 </project>

    配置application.yml

     1 server:
     2   servlet:
     3     context-path: /quartz
     4 spring:
     5   datasource:
     6     #1.JDBC
     7     type: com.alibaba.druid.pool.DruidDataSource
     8     driver-class-name: com.mysql.jdbc.Driver
     9     url: jdbc:mysql://localhost:3306/j2ee?useUnicode=true&characterEncoding=utf8
    10     username: root
    11     password: 12345
    12     druid:
    13       #2.连接池配置
    14       #初始化连接池的连接数量 大小,最小,最大
    15       initial-size: 5
    16       min-idle: 5
    17       max-active: 20
    18       #配置获取连接等待超时的时间
    19       max-wait: 60000
    20       #配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
    21       time-between-eviction-runs-millis: 60000
    22       # 配置一个连接在池中最小生存的时间,单位是毫秒
    23       min-evictable-idle-time-millis: 30000
    24       validation-query: SELECT 1 FROM DUAL
    25       test-while-idle: true
    26       test-on-borrow: true
    27       test-on-return: false
    28       # 是否缓存preparedStatement,也就是PSCache  官方建议MySQL下建议关闭   个人建议如果想用SQL防火墙 建议打开
    29       pool-prepared-statements: true
    30       max-pool-prepared-statement-per-connection-size: 20
    31       # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    32       filter:
    33         stat:
    34           merge-sql: true
    35           slow-sql-millis: 5000
    36       #3.基础监控配置
    37       web-stat-filter:
    38         enabled: true
    39         url-pattern: /*
    40         #设置不统计哪些URL
    41         exclusions: "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"
    42         session-stat-enable: true
    43         session-stat-max-count: 100
    44       stat-view-servlet:
    45         enabled: true
    46         url-pattern: /druid/*
    47         reset-enable: true
    48         #设置监控页面的登录名和密码
    49         login-username: admin
    50         login-password: admin
    51         allow: 127.0.0.1
    52         #deny: 192.168.1.100
    53 
    54 #显示日志
    55 logging:
    56   level:
    57     com.yuan.quartz02.mapper: debug

    Quartz02Application

     1 package com.yuan.quartz02;
     2 
     3 import org.mybatis.spring.annotation.MapperScan;
     4 import org.springframework.boot.SpringApplication;
     5 import org.springframework.boot.autoconfigure.SpringBootApplication;
     6 import org.springframework.scheduling.annotation.EnableScheduling;
     7 import org.springframework.transaction.annotation.EnableTransactionManagement;
     8 
     9 @MapperScan("com.yuan.quartz02.mapper")
    10 @EnableTransactionManagement
    11 @EnableScheduling
    12 @SpringBootApplication
    13 public class Quartz02Application {
    14 
    15     public static void main(String[] args) {
    16         SpringApplication.run(Quartz02Application.class, args);
    17     }
    18 
    19 }

    添加逆向生成代码generatorConfig.xml

     1 <?xml version="1.0" encoding="UTF-8" ?>
     2 <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
     3         "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
     4 <generatorConfiguration>
     5     <!-- 引入配置文件 -->
     6     <properties resource="jdbc.properties"/>
     7 
     8     <!--指定数据库jdbc驱动jar包的位置-->
     9     <classPathEntry location="D:Maven-folderapache-maven-3.5.0-binapache-maven-3.5.0mvn_repositorymysqlmysql-connector-java5.1.44mysql-connector-java-5.1.44.jar"/>
    10 
    11     <!-- 一个数据库一个context -->
    12     <context id="infoGuardian">
    13         <!-- 注释 -->
    14         <commentGenerator>
    15             <property name="suppressAllComments" value="true"/><!-- 是否取消注释 -->
    16             <property name="suppressDate" value="true"/> <!-- 是否生成注释代时间戳 -->
    17         </commentGenerator>
    18 
    19         <!-- jdbc连接 -->
    20         <jdbcConnection driverClass="${jdbc.driver}"
    21                         connectionURL="${jdbc.url}" userId="${jdbc.username}" password="${jdbc.password}"/>
    22 
    23         <!-- 类型转换 -->
    24         <javaTypeResolver>
    25             <!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
    26             <property name="forceBigDecimals" value="false"/>
    27         </javaTypeResolver>
    28 
    29         <!-- 01 指定javaBean生成的位置 -->
    30         <!-- targetPackage:指定生成的model生成所在的包名 -->
    31         <!-- targetProject:指定在该项目下所在的路径  -->
    32         <javaModelGenerator targetPackage="com.yuan.quartz02.model"
    33                             targetProject="src/main/java">
    34             <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
    35             <property name="enableSubPackages" value="false"/>
    36             <!-- 是否对model添加构造函数 -->
    37             <property name="constructorBased" value="true"/>
    38             <!-- 是否针对string类型的字段在set的时候进行trim调用 -->
    39             <property name="trimStrings" value="false"/>
    40             <!-- 建立的Model对象是否 不可改变  即生成的Model对象不会有 setter方法,只有构造方法 -->
    41             <property name="immutable" value="false"/>
    42         </javaModelGenerator>
    43 
    44         <!-- 02 指定sql映射文件生成的位置 -->
    45         <sqlMapGenerator targetPackage="com.yuan.quartz02.mapper"
    46                          targetProject="src/main/java">
    47             <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
    48             <property name="enableSubPackages" value="false"/>
    49         </sqlMapGenerator>
    50 
    51         <!-- 03 生成XxxMapper接口 -->
    52         <!-- type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象 -->
    53         <!-- type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象 -->
    54         <!-- type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口 -->
    55         <javaClientGenerator targetPackage="com.yuan.quartz02.mapper"
    56                              targetProject="src/main/java" type="XMLMAPPER">
    57             <!-- 是否在当前路径下新加一层schema,false路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
    58             <property name="enableSubPackages" value="false"/>
    59         </javaClientGenerator>
    60 
    61         <!-- 配置表信息 -->
    62         <table schema="" tableName="t_schedule_trigger" domainObjectName="ScheduleTrigger"
    63                enableCountByExample="false" enableDeleteByExample="false"
    64                enableSelectByExample="false" enableUpdateByExample="false">
    65             <property name="useActualColumnNames" value="true" />
    66         </table>
    67         <table schema="" tableName="t_schedule_trigger_param" domainObjectName="ScheduleTriggerParam"
    68                enableCountByExample="false" enableDeleteByExample="false"
    69                enableSelectByExample="false" enableUpdateByExample="false">
    70             <property name="useActualColumnNames" value="true" />
    71         </table>
    72 
    73     </context>
    74 </generatorConfiguration>

    jdbc.properties

    1 jdbc.driver=com.mysql.jdbc.Driver
    2 jdbc.url=jdbc:mysql://localhost:3306/j2ee?useUnicode=true&characterEncoding=UTF-8
    3 jdbc.username=root
    4 jdbc.password=12345

    ScheduleTriggerMapper

     1 package com.yuan.quartz02.mapper;
     2 
     3 import com.yuan.quartz02.model.ScheduleTrigger;
     4 import org.springframework.stereotype.Repository;
     5 
     6 import java.util.List;
     7 
     8 @Repository
     9 public interface ScheduleTriggerMapper {
    10     int deleteByPrimaryKey(Integer id);
    11 
    12     int insert(ScheduleTrigger record);
    13 
    14     int insertSelective(ScheduleTrigger record);
    15 
    16     ScheduleTrigger selectByPrimaryKey(Integer id);
    17 
    18     int updateByPrimaryKeySelective(ScheduleTrigger record);
    19 
    20     int updateByPrimaryKey(ScheduleTrigger record);
    21 
    22     /**
    23      * 查询触发器中包含的所有任务
    24      * @return
    25      */
    26     List<ScheduleTrigger> queryScheduleTriggerLst();
    27 }

    在自动生成的ScheduleTriggerMapper.xml中添加

    1   <select id="queryScheduleTriggerLst" resultType="com.yuan.quartz02.model.ScheduleTrigger">
    2     select <include refid="Base_Column_List"/>
    3     from t_schedule_trigger
    4   </select>

    ScheduleTriggerParamMapper

     1 package com.yuan.quartz02.mapper;
     2 
     3 import com.yuan.quartz02.model.ScheduleTriggerParam;
     4 import org.springframework.stereotype.Repository;
     5 
     6 import java.util.List;
     7 
     8 @Repository
     9 public interface ScheduleTriggerParamMapper {
    10     int deleteByPrimaryKey(Integer param_id);
    11 
    12     int insert(ScheduleTriggerParam record);
    13 
    14     int insertSelective(ScheduleTriggerParam record);
    15 
    16     ScheduleTriggerParam selectByPrimaryKey(Integer param_id);
    17 
    18     int updateByPrimaryKeySelective(ScheduleTriggerParam record);
    19 
    20     int updateByPrimaryKey(ScheduleTriggerParam record);
    21 
    22     /**
    23      * 查询出当前任务类对应所需的参数
    24      * @param triggerId
    25      * @return
    26      */
    27     List<ScheduleTriggerParam> queryScheduleParamLst(Integer triggerId);
    28 }

    在自动生成的ScheduleTriggerParamMapper.xml中添加

    1   <select id="queryScheduleParamLst" resultType="com.yuan.quartz02.model.ScheduleTriggerParam">
    2     select <include refid="Base_Column_List"/>
    3     from t_schedule_trigger_param where schedule_trigger_id=#{triggerId}
    4   </select>

    service层

    ScheduleTriggerService

     1 package com.yuan.quartz02.service;
     2 
     3 import com.yuan.quartz02.model.ScheduleTrigger;
     4 
     5 import java.util.List;
     6 public interface ScheduleTriggerService {
     7     int deleteByPrimaryKey(Integer id);
     8 
     9     int insert(ScheduleTrigger record);
    10 
    11     int insertSelective(ScheduleTrigger record);
    12 
    13     ScheduleTrigger selectByPrimaryKey(Integer id);
    14 
    15     int updateByPrimaryKeySelective(ScheduleTrigger record);
    16 
    17     int updateByPrimaryKey(ScheduleTrigger record);
    18 
    19     /**
    20      * 查询触发器中包含的所有任务
    21      * @return
    22      */
    23     List<ScheduleTrigger> queryScheduleTriggerLst();
    24 
    25 }

    ScheduleTriggerServiceImpl

      1 package com.yuan.quartz02.service.impl;
      2 
      3 import com.yuan.quartz02.mapper.ScheduleTriggerMapper;
      4 import com.yuan.quartz02.mapper.ScheduleTriggerParamMapper;
      5 import com.yuan.quartz02.model.ScheduleTrigger;
      6 import com.yuan.quartz02.model.ScheduleTriggerParam;
      7 import com.yuan.quartz02.service.ScheduleTriggerService;
      8 import org.quartz.*;
      9 import org.springframework.beans.factory.annotation.Autowired;
     10 import org.springframework.scheduling.annotation.Scheduled;
     11 import org.springframework.stereotype.Service;
     12 
     13 import java.util.List;
     14 
     15 @Service
     16 public class ScheduleTriggerServiceImpl implements ScheduleTriggerService {
     17 
     18     @Autowired
     19     private ScheduleTriggerMapper scheduleTriggerMapper;
     20 
     21     @Autowired
     22     private ScheduleTriggerParamMapper scheduleTriggerParamMapper;
     23 
     24     @Autowired
     25     private Scheduler scheduler;
     26 
     27     @Scheduled(cron = "0/10 * * * * ?")
     28     public void refreshScheduler(){
     29         try {
     30             List<ScheduleTrigger> scheduleTriggers =
     31                     scheduleTriggerMapper.queryScheduleTriggerLst();
     32             if(null!=scheduleTriggers){
     33                 for (ScheduleTrigger scheduleTrigger : scheduleTriggers) {
     34                     String cron = scheduleTrigger.getCron();  //表达式
     35                     String jobName = scheduleTrigger.getJob_name(); //任务名称
     36                     String jobGroup = scheduleTrigger.getJob_group(); //任务分组
     37                     String status = scheduleTrigger.getStatus();  //任务状态
     38 
     39                     //JobName+JobGroup=Primary Key
     40                     //根据jobName和jobGroup生成TriggerKey
     41                     TriggerKey triggerKey =
     42                             TriggerKey.triggerKey(jobName, jobGroup);
     43                     //根据TriggerKey到Scheduler调度器中获取触发器
     44                     CronTrigger cronTrigger = (CronTrigger)
     45                             scheduler.getTrigger(triggerKey);
     46 
     47                     if(null==cronTrigger){
     48                         if(status.equals("0"))
     49                             continue;
     50                         System.out.println("创建调度器");
     51                         //创建任务详情
     52                         JobDetail jobDetail=
     53                                 JobBuilder.newJob((Class<? extends Job>) Class.forName(jobName))
     54                                 .withIdentity(jobName,jobGroup)
     55                                 .build();
     56 
     57                         //往Job任务中传递参数
     58                         JobDataMap jobDataMap = jobDetail.getJobDataMap();
     59                         List<ScheduleTriggerParam> params =
     60                                 scheduleTriggerParamMapper.queryScheduleParamLst(scheduleTrigger.getId());
     61                         for (ScheduleTriggerParam param : params) {
     62                             jobDataMap.put(param.getName(),param.getValue());
     63                         }
     64 
     65                         //创建表达式调度器
     66                         CronScheduleBuilder cronSchedule =
     67                                 CronScheduleBuilder.cronSchedule(cron);
     68 
     69                         //创建Trigger
     70                         cronTrigger=TriggerBuilder.newTrigger()
     71                                     .withIdentity(jobName,jobGroup)
     72                                     .withSchedule(cronSchedule)
     73                                     .build();
     74 
     75                         //将jobDetail和Trigger注入到scheduler调度器中
     76                         scheduler.scheduleJob(jobDetail,cronTrigger);
     77                     }else{
     78                         //System.out.println("Quartz 调度任务中已存在该任务");
     79                         if(status.equals("0")){
     80                             JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
     81                             scheduler.deleteJob(jobKey);
     82                             continue;
     83                         }
     84                         //调度器中的表达式
     85                         String cronExpression =
     86                                 cronTrigger.getCronExpression();
     87 
     88                         if(!cron.equals(cronExpression)){
     89                             //创建表达式调度器
     90                             CronScheduleBuilder cronSchedule =
     91                                     CronScheduleBuilder.cronSchedule(cron);
     92 
     93                             //重构
     94                             cronTrigger=cronTrigger.getTriggerBuilder()
     95                                     .withIdentity(triggerKey)
     96                                     .withSchedule(cronSchedule)
     97                                     .build();
     98 
     99                             //刷新调度器
    100                             scheduler.rescheduleJob(triggerKey,cronTrigger);
    101                         }
    102                     }
    103                 }
    104             }
    105         } catch (Exception e) {
    106             e.printStackTrace();
    107         }
    108     }
    109 
    110     @Override
    111     public int deleteByPrimaryKey(Integer id) {
    112         return scheduleTriggerMapper.deleteByPrimaryKey(id);
    113     }
    114 
    115     @Override
    116     public int insert(ScheduleTrigger record) {
    117         return scheduleTriggerMapper.insert(record);
    118     }
    119 
    120     @Override
    121     public int insertSelective(ScheduleTrigger record) {
    122         return scheduleTriggerMapper.insertSelective(record);
    123     }
    124 
    125     @Override
    126     public ScheduleTrigger selectByPrimaryKey(Integer id) {
    127         return scheduleTriggerMapper.selectByPrimaryKey(id);
    128     }
    129 
    130     @Override
    131     public int updateByPrimaryKeySelective(ScheduleTrigger record) {
    132         return scheduleTriggerMapper.updateByPrimaryKeySelective(record);
    133     }
    134 
    135     @Override
    136     public int updateByPrimaryKey(ScheduleTrigger record) {
    137         return scheduleTriggerMapper.updateByPrimaryKey(record);
    138     }
    139 
    140     @Override
    141     public List<ScheduleTrigger> queryScheduleTriggerLst() {
    142         return scheduleTriggerMapper.queryScheduleTriggerLst();
    143     }
    144 }

     ScheduleTriggerParamService

     1 package com.yuan.quartz02.service;
     2 
     3 import com.yuan.quartz02.model.ScheduleTriggerParam;
     4 
     5 import java.util.List;
     6 
     7 public interface ScheduleTriggerParamService {
     8 
     9     /**
    10      * 查询出当前任务类对应所需的参数
    11      * @param triggerId
    12      * @return
    13      */
    14     List<ScheduleTriggerParam> queryScheduleParamLst(Integer triggerId);
    15 }

    ScheduleTriggerParamServiceImpl

     1 package com.yuan.quartz02.service.impl;
     2 
     3 import com.yuan.quartz02.mapper.ScheduleTriggerParamMapper;
     4 import com.yuan.quartz02.model.ScheduleTriggerParam;
     5 import com.yuan.quartz02.service.ScheduleTriggerParamService;
     6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.stereotype.Service;
     8 
     9 import java.util.List;
    10 
    11 @Service
    12 public class ScheduleTriggerParamServiceImpl implements ScheduleTriggerParamService {
    13 
    14     @Autowired
    15     private ScheduleTriggerParamMapper scheduleTriggerParamMapper;
    16 
    17     @Override
    18     public List<ScheduleTriggerParam> queryScheduleParamLst(Integer triggerId) {
    19         return scheduleTriggerParamMapper.queryScheduleParamLst(triggerId);
    20     }
    21 }

    读取数据库中表达式启动定时任务

    myjob

     1 package com.yuan.quartz02.quartz;
     2 
     3 import lombok.extern.slf4j.Slf4j;
     4 import org.quartz.Job;
     5 import org.quartz.JobExecutionContext;
     6 import org.quartz.JobExecutionException;
     7 import org.springframework.stereotype.Component;
     8 
     9 import java.util.Date;
    10 
    11 @Component
    12 @Slf4j
    13 public class MyJob implements Job {
    14 
    15     @Override
    16     public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    17         System.out.println("MyJob是一个空的任务计划,时间:"+new Date().toLocaleString());
    18     }
    19 }

     

    Spring自带定时任务每10s执行一次,查询自定义触发器表,

    获取到具体的作业类及任务表达式,quartz的任务为每5s执行一次,所以打印如上

    更改定时任务状态

    更改数据库调度器表t_schedule_trigger的state状态

    取数据库中表达式启动定时任务

    数据库表t_schedule_trigger配置

    当禁用该触发器时,那么程序只会执行spring自带的定时任务,每10s执行一次查询,所以打印语句如上。

    MyJob1

     1 package com.yuan.quartz02.quartz;
     2 
     3 import com.yuan.quartz02.service.ScheduleTriggerParamService;
     4 import lombok.extern.slf4j.Slf4j;
     5 import org.quartz.*;
     6 import org.springframework.beans.factory.annotation.Autowired;
     7 import org.springframework.stereotype.Component;
     8 
     9 import java.util.Date;
    10 
    11 @Component
    12 @Slf4j
    13 public class MyJob1 implements Job {
    14 
    15     @Autowired
    16     private ScheduleTriggerParamService scheduleTriggerParamService;
    17 
    18     @Override
    19     public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    20         JobDetail jobDetail =
    21                 jobExecutionContext.getJobDetail();
    22         JobDataMap jobDataMap = jobDetail.getJobDataMap();
    23         System.err.println(new Date().toLocaleString()+"-->携带参数个数:"+jobDataMap.size());
    24     }
    25 }

    程序执行spring自带的定时任务,每10s执行一次查询,查询t_schedule_trigger表,

    调度器表中有两个调度器,都是每5s执行一次,其中一个调度器是需要携带参数的,

    携带的参数在t_schedule_trigger_param表中,所以一开始调度器启动的时候需要查询t_schedule_trigger_param表数据,最终打印语句如上。

    更改定时任务规则

    t_schedule_trigger

    程序执行spring自带的定时任务,每10s执行一次查询,查询t_schedule_trigger表

    控制器
    QuartzController

     1 package com.yuan.quartz02.controller;
     2 
     3 import com.yuan.quartz02.model.ScheduleTrigger;
     4 import com.yuan.quartz02.service.ScheduleTriggerService;
     5 import org.springframework.beans.factory.annotation.Autowired;
     6 import org.springframework.stereotype.Controller;
     7 import org.springframework.web.bind.annotation.PathVariable;
     8 import org.springframework.web.bind.annotation.RequestMapping;
     9 import org.springframework.web.bind.annotation.ResponseBody;
    10 import org.springframework.web.servlet.ModelAndView;
    11 
    12 import java.util.List;
    13 
    14 @Controller
    15 @RequestMapping("/quartz")
    16 public class QuartzController {
    17 
    18     @Autowired
    19     private ScheduleTriggerService scheduleTriggerService;
    20 
    21     @RequestMapping("/list")
    22     public ModelAndView getAll(){
    23         ModelAndView modelAndView = new ModelAndView();
    24         List<ScheduleTrigger> list = scheduleTriggerService.queryScheduleTriggerLst();
    25         modelAndView.addObject("quartzList",list);
    26         modelAndView.setViewName("/index");
    27         return modelAndView;
    28     }
    29 
    30     @RequestMapping("/edit")
    31     public String editStatus(ScheduleTrigger scheduleTrigger){
    32         int n = scheduleTriggerService.updateByPrimaryKeySelective(scheduleTrigger);
    33         return "redirect:/quartz/list";
    34     }
    35 
    36     @RequestMapping("/proSave/{id}")
    37     public ModelAndView proSave(@PathVariable(value = "id") Integer id){
    38         ModelAndView modelAndView=new ModelAndView();
    39         ScheduleTrigger scheduleTrigger = scheduleTriggerService.selectByPrimaryKey(id);
    40         modelAndView.addObject("schedule",scheduleTrigger);
    41         modelAndView.setViewName("/edit");
    42         return modelAndView;
    43     }
    44 
    45 }

    页面代码

    index.html

     1 <!DOCTYPE html>
     2 <html xmlns:th="http://www.thymeleaf.org">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>quartz定时任务管理</title>
     6 </head>
     7 <body>
     8 <h1 style="text-align: center">定时任务管理</h1>
     9 <table style="text-align: center" align="center" border="1px" width="80%">
    10     <tr>
    11         <td>任务id</td>
    12         <td>任务表达式</td>
    13         <td>任务状态</td>
    14         <td>job工作类</td>
    15         <td>job分组</td>
    16         <td>操作</td>
    17     </tr>
    18     <tr th:each="q : ${quartzList}">
    19         <td th:text="${q.id}"></td>
    20         <td th:text="${q.cron}"></td>
    21         <td th:text="${q.status}"></td>
    22         <td th:text="${q.job_name}"></td>
    23         <td th:text="${q.job_group}"></td>
    24         <td th:switch ="${q.status} == 0">
    25             <a th:case="true" th:href="@{/quartz/edit(id=${q.id},status=1)}">启动</a>
    26             <a th:case="false" th:href="@{/quartz/edit(id=${q.id},status=0)}">停止</a>
    27             <a th:href="@{'/quartz/proSave/'+${q.id}}">编辑</a>
    28         </td>
    29     </tr>
    30 </table>
    31 
    32 
    33 </body>
    34 </html>

    edit.html

     1 <!DOCTYPE html>
     2 <html xmlns:th="http://www.thymeleaf.org">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>编辑定时任务</title>
     6 </head>
     7 <body>
     8 <h1>编辑定时任务</h1>
     9 <form th:action="@{/quartz/edit}" method="post">
    10     <input type="hidden" name="id" th:value="${schedule.id}" />
    11     任务表达式: <input width="300px" type="text" name="cron" th:value="${schedule.cron}" /></br>
    12     job工作类: <input width="300px" type="text" name="job_name" th:value="${schedule.job_name}" /></br>
    13     job分组:<input width="300px" type="text" name="job_group" th:value="${schedule.job_group}" /></br>
    14     <input type="submit" value="提交"/>
    15 </form>
    16 </body>
    17 </html>

    页面效果

     

     谢谢观看!!!

  • 相关阅读:
    74.Interesting Sequence(有趣的数列)(拓扑排序)
    CODEVS 1746 贪吃的九头龙
    NYOJ 110 剑客决斗
    CODEVS 2451 互不侵犯
    洛谷 P1896 互不侵犯King
    洛谷 P1066 2^k进制数
    洛谷 P1656 炸铁路
    洛谷 P1830 轰炸Ⅲ
    CODEVS 1051 接龙游戏
    POJ 3461 Oulipo
  • 原文地址:https://www.cnblogs.com/ly-0919/p/11982955.html
Copyright © 2011-2022 走看看