阅读 186

SpringBoot结合Quartz实现数据库存储

本文主要介绍了SpringBoot+Quartz+数据库存储,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

目录
  • 一、先创建一个SpringBoot项目

  • 二、导入依赖 

  • 三、 导入DruidConnectionProvider.java(Druid连接池的Quartz扩展类)

  • 四、 修改自定义quartz.properties配置(在项目中添加quartz.properties文件(这样就不会加载自带的properties文件) )

  • 五、自定义MyJobFactory,解决spring不能在quartz中注入bean的问题

  • 六、创建调度器schedule

  • 七、 创建自定义任务

  • 八、 更新quartz中的任务

  • 小结:

一、先创建一个SpringBoot项目

还有一个截屏忘了截屏,就是选择保存路径选择一下就点Finish就可以了。 

更改application.properties为application.yml

application.yml文件如下

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

二、导入依赖 

1.导入Quartz依赖

1
2
3
4
5
6
7
8
9
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz-jobs</artifactId>
    <version>2.2.1</version>
 </dependency>
 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
 </dependency>

2.用于我用的是Druid数据库连接池,所以我需要更换成Druid连接池,先引入Druid依赖。

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

三、 导入DruidConnectionProvider.java(Druid连接池的Quartz扩展类)

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

四、 修改自定义quartz.properties配置(在项目中添加quartz.properties文件(这样就不会加载自带的properties文件) )

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#
#============================================================================
# Configure Main Scheduler Properties \u8C03\u5EA6\u5668\u5C5E\u6027
#============================================================================
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount= 10
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
org.quartz.jobStore.misfireThreshold: 60000
#============================================================================
# Configure JobStore
#============================================================================
#\u5B58\u50A8\u65B9\u5F0F\u4F7F\u7528JobStoreTX\uFF0C\u4E5F\u5C31\u662F\u6570\u636E\u5E93
org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#\u4F7F\u7528\u81EA\u5DF1\u7684\u914D\u7F6E\u6587\u4EF6
org.quartz.jobStore.useProperties:true
#\u6570\u636E\u5E93\u4E2Dquartz\u8868\u7684\u8868\u540D\u524D\u7F00
org.quartz.jobStore.tablePrefix:qrtz_
org.quartz.jobStore.dataSource:qzDS
#\u662F\u5426\u4F7F\u7528\u96C6\u7FA4\uFF08\u5982\u679C\u9879\u76EE\u53EA\u90E8\u7F72\u5230 \u4E00\u53F0\u670D\u52A1\u5668\uFF0C\u5C31\u4E0D\u7528\u4E86\uFF09
org.quartz.jobStore.isClustered = true
#============================================================================
# Configure Datasources
#============================================================================
#\u914D\u7F6E\u6570\u636E\u5E93\u6E90
org.quartz.dataSource.qzDS.connectionProvider.class: com.zking.quartz02.utils.DruidConnectionProvider
org.quartz.dataSource.qzDS.driver: com.mysql.cj.jdbc.Driver
#修改为自己的数据库名称、用户名和密码
org.quartz.dataSource.qzDS.URL: jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
org.quartz.dataSource.qzDS.user: root
org.quartz.dataSource.qzDS.password: 123
org.quartz.dataSource.qzDS.maxConnection: 10

在数据库中创建quartz相关的表
   进入quartz的官网http://www.quartz-scheduler.org/,点击Downloads,
   下载后在目录\docs\dbTables下有常用数据库创建quartz表的脚本,例如:“tables_mysql.sql”

五、自定义MyJobFactory,解决spring不能在quartz中注入bean的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.zking.quartz02.quartz;
  
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
  
//解决spring不能在quartz中注入bean的问题
@Component
public class MyJobFactory extends AdaptableJobFactory {
  
    @Autowired
    private AutowireCapableBeanFactory autowireCapableBeanFactory;
  
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        autowireCapableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

六、创建调度器schedule


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.zking.quartz02.quartz;
  
//quartz配置类将调度器交给spring管理
  
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
  
import java.io.IOException;
import java.util.Properties;
  
@Configuration
public class QuartzConfiguration {
  
    @Autowired
    private  MyJobFactory myJobFactory;
  
    @Bean
    public Scheduler scheduler(){
        return this.getSchedulerFactoryBean().getScheduler();
    }
  
    //读取自定义配置文件,获取调度器工厂
    @Bean
    public SchedulerFactoryBean getSchedulerFactoryBean(){
        //1.创建SchedulerFactoryBean sc=new SchedulerFactoryBean
        SchedulerFactoryBean sc=new SchedulerFactoryBean();
        //2.加载自定义的quartz.properties
        sc.setQuartzProperties(this.getProperties());
        //3.设置自定义的MyJobFactory
        sc.setJobFactory(myJobFactory);
  
        return sc;
    }
  
    //读取配置文件
    @Bean
    public Properties getProperties(){
  
        try {
            PropertiesFactoryBean propertiesFactoryBean =
                    new PropertiesFactoryBean();
  
            //设置自定义配置文件位置
            propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
            //读取配置文件
            propertiesFactoryBean.afterPropertiesSet();
  
            return  propertiesFactoryBean.getObject();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
  
  
    }
  
  
}

七、 创建自定义任务

 首先我们需要自己创建一张表t_schedule_trigger,用来存放trigger的信息,然后从数据库读取这些信息来随时更新定时任务
   注意:job_name存放的任务类的全路径,在quartz中通过jobName和jobGroup来确定trigger的唯一性,所以这两列为联合唯一索引 

t_schedule_trigger和t_schedule_trigger_param表生成的sql代码如下(去执行一下sql语句即可)

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

   注1:t_schedule_trigger的子表t_schedule_trigger_param还可以用来传递额外添加到任务中的参数

   注2:实现org.quartz.Job或org.springframework.scheduling.quartz.QuartzJobBean创建任务,可通过JobExecutionContext传参

八、 更新quartz中的任务

首先我们将t_schedule_trigger和t_schedule_trigger_param通过generatorConfig.xml自动生成实体类,XXmapper.java,XXmapper.xml.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
    <!-- 引入配置文件 -->
<!--    <properties resource="jdbc.properties"/>-->
  
    <!--指定数据库jdbc驱动jar包的位置-->
    <classPathEntry location="D:\\installpath\\apache-maven-3.5.4\\jar\\mysql\\mysql-connector-java\\5.1.44\\mysql-connector-java-5.1.44.jar"/>
  
    <!-- 一个数据库一个context -->
    <context id="infoGuardian">
        <!-- 注释 -->
        <commentGenerator>
            <property name="suppressAllComments" value="true"/><!-- 是否取消注释 -->
            <property name="suppressDate" value="true"/> <!-- 是否生成注释代时间戳 -->
        </commentGenerator>
  
        <!-- jdbc连接 -->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/quartz?useUnicode=true&amp;characterEncoding=UTF-8" userId="root" password="123"/>
  
        <!-- 类型转换 -->
        <javaTypeResolver>
            <!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
  
        <!-- 01 指定javaBean生成的位置 -->
        <!-- targetPackage:指定生成的model生成所在的包名 -->
        <!-- targetProject:指定在该项目下所在的路径  -->
        <javaModelGenerator targetPackage="com.zking.quartz02.model"
                            targetProject="src/main/java">
            <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
            <property name="enableSubPackages" value="false"/>
            <!-- 是否对model添加构造函数 -->
            <property name="constructorBased" value="true"/>
            <!-- 是否针对string类型的字段在set的时候进行trim调用 -->
            <property name="trimStrings" value="false"/>
            <!-- 建立的Model对象是否 不可改变  即生成的Model对象不会有 setter方法,只有构造方法 -->
            <property name="immutable" value="false"/>
        </javaModelGenerator>
  
        <!-- 02 指定sql映射文件生成的位置 -->
        <sqlMapGenerator targetPackage="mapper"
                         targetProject="src/main/resources">
            <!-- 是否允许子包,即targetPackage.schemaName.tableName -->
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>
  
        <!-- 03 生成XxxMapper接口 -->
        <!-- type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象 -->
        <!-- type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象 -->
        <!-- type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口 -->
        <javaClientGenerator targetPackage="com.zking.quartz02.mapper"
                             targetProject="src/main/java" type="XMLMAPPER">
            <!-- 是否在当前路径下新加一层schema,false路径com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] -->
            <property name="enableSubPackages" value="false"/>
        </javaClientGenerator>
  
        <!-- 配置表信息 -->
        <!-- schema即为数据库名 -->
        <!-- tableName为对应的数据库表 -->
        <!-- domainObjectName是要生成的实体类 -->
        <!-- enable*ByExample是否生成 example类 -->
        <!--<table schema="" tableName="t_book" domainObjectName="Book"-->
               <!--enableCountByExample="false" enableDeleteByExample="false"-->
               <!--enableSelectByExample="false" enableUpdateByExample="false">-->
            <!--&lt;!&ndash; 忽略列,不生成bean 字段 &ndash;&gt;-->
            <!--&lt;!&ndash; <ignoreColumn column="FRED" /> &ndash;&gt;-->
            <!--&lt;!&ndash; 指定列的java数据类型 &ndash;&gt;-->
            <!--&lt;!&ndash; <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" /> &ndash;&gt;-->
        <!--</table>-->
  
        <table schema="" tableName="t_schedule_trigger_param" domainObjectName="ScheduleTriggerParam"
               enableCountByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" enableUpdateByExample="false">
            <!-- 忽略列,不生成bean 字段 -->
            <!-- <ignoreColumn column="FRED" /> -->
            <!-- 指定列的java数据类型 -->
            <!-- <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" /> -->
        </table>
  
        <table schema="" tableName="t_schedule_trigger" domainObjectName="ScheduleTrigger"
               enableCountByExample="false" enableDeleteByExample="false"
               enableSelectByExample="false" enableUpdateByExample="false">
            <!-- 忽略列,不生成bean 字段 -->
            <!-- <ignoreColumn column="FRED" /> -->
            <!-- 指定列的java数据类型 -->
            <!-- <columnOverride column="LONG_VARCHAR_FIELD" jdbcType="VARCHAR" /> -->
        </table>
  
    </context>
</generatorConfiguration>

记得修改数据库jdbc驱动jar包的位置为自己数据库jdbc驱动jar包的位置,jdbc连接数据库名、用户名和密码改为自己的。

注意:targetPackage改成自己的包名。

自动生成操作

命令:mybatis-generator:generate -e

注意:实体类上加一个@Data,XXmapper.java上加一个@Repository自己需要写一个查询全部的方法。

写一个IScheduleService接口,用来定时刷新任务,更新调度器中的任务

1
2
3
4
5
6
7
package com.zking.quartz02.service;
  
public interface IScheduleService {
  
    //定时刷新任务,更新调度器中的任务
    public void refresh();
}

实现IScheduleService接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package com.zking.quartz02.service.impl;
  
import com.zking.quartz02.mapper.ScheduleTriggerMapper;
import com.zking.quartz02.mapper.ScheduleTriggerParamMapper;
import com.zking.quartz02.model.ScheduleTrigger;
import com.zking.quartz02.model.ScheduleTriggerParam;
import com.zking.quartz02.service.IScheduleService;
import org.quartz.*;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
  
import javax.annotation.Resource;
import java.util.List;
  
@Service
public class ScheduleServiceImpl implements IScheduleService {
  
    @Resource
    private ScheduleTriggerMapper scheduleTriggerMapper;
  
    @Resource
    private ScheduleTriggerParamMapper scheduleTriggerParamMapper;
  
    @Resource
    private Scheduler scheduler;
  
    @Scheduled(cron = "*/10 * * * * ?")
    @Override
    public void refresh() {
  
        try {
            //1.查询数据库中所有的任务
            List<ScheduleTrigger> scheduleTriggers =
                    scheduleTriggerMapper.listScheduleTrigger();
  
            //2.遍历所有任务
            for (ScheduleTrigger scheduleTrigger : scheduleTriggers) {
                Integer id = scheduleTrigger.getId();
                String cron = scheduleTrigger.getCron();
                String status = scheduleTrigger.getStatus();
                String jobName = scheduleTrigger.getJobName();
                String jobGroup = scheduleTrigger.getJobGroup();
  
                //设置triggerKey
                TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
  
                //通过triggerKey获取调度器中的触发器
                CronTrigger cronTrigger = (CronTrigger)scheduler.getTrigger(triggerKey);
  
                if(null==cronTrigger){//如果为空,表示调度器中没有该任务,不存在就添加任务
                    if("0".equals(status)){//如果该任务状态为0,表示该任务不用添加,此次循环结束
                        continue;
                    }
  
                    //创建触发器
                    CronTrigger cronTrigger1 = TriggerBuilder.newTrigger()
                            .withIdentity(jobName, jobGroup)
                            .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                            .build();
  
                    //创建工作详情实例
                    JobDetail jobDetail = JobBuilder.newJob((Class<? extends Job>) Class.forName(jobName))
                            .withIdentity(jobName, jobGroup)
                            .build();
  
                    JobDataMap jobDataMap = jobDetail.getJobDataMap();
  
  
                    //查询该任务中所有的参数
                    List<ScheduleTriggerParam> scheduleTriggerParams = scheduleTriggerParamMapper.listScheduleTriggerParamById(id);
  
  
                    //遍历所有参数,将参数设置到jobDataMap中
                    for (ScheduleTriggerParam scheduleTriggerParam : scheduleTriggerParams) {
                        jobDataMap.put(scheduleTriggerParam.getName(),scheduleTriggerParam.getValue());
                    }
  
  
                    //添加任务,将触发器和工作详情实例添加到调度器中
                    scheduler.scheduleJob(jobDetail,cronTrigger1);
  
  
                }else{//如果不为空,表示调度器中存在该任务
                    if("0".equals(status)){//如果任务状态改为禁用,移除该任务
                        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
                        scheduler.deleteJob(jobKey);//移除任务
                    }
  
  
  
                    //如果调度器中的触发器的表达式和数据库中的表达式不一致
  
                    //获取调度器中触发器的表达式
                    String cronExpression = cronTrigger.getCronExpression();
                    if(!cronExpression.equals(cron)){//不一致
                        //重新创建新的触发器
                        CronTrigger cronTrigger2 = TriggerBuilder.newTrigger()
                                .withIdentity(jobName, jobGroup)
                                .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                                .build();
  
                        //更新调度器中的触发器
                        scheduler.rescheduleJob(triggerKey,cronTrigger2);
                    }
  
  
  
  
  
                }
            }
  
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
  
    }
}

1) service层实现类使用@Scheduled注解声明一个方法用于定时刷新数据库中的调度任务;
 2) 使用@Resource注解注入Scheduler,在第5点中已装配到Spring上下文;

 3) 在启动类上加入@MapperScan(指定要变成实现类的接口所在的包路径,比如我的就是com.zking.quartz02.mapper),然后包下面的所有接口在编译之后都会生成相应的实现类;
 4) 在启动类上加入@EnableScheduling启动Spring自带定时器任务;

小结:

   要搞清楚一个问题:从数据库读取任务信息动态生成定时任务,和把quartz持久化到数据库是没有关系的。
   前者是我们自己定义的业务表,而后者是quartz使用自己的表来存储信息。持久化到数据库后,
   就算服务器重启或是多个quartz节点也没关系,因为他们共享数据库中的任务信息。

到此这篇关于SpringBoot结合Quartz实现数据库存储的文章就介绍到这了

原文链接:https://blog.csdn.net/wjs0513/article/details/122522938


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐