还有一个截屏忘了截屏,就是选择保存路径选择一下就点finish就可以了。
更改application.properties为application.yml
application.yml文件如下
rver: 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?uunicode=true&characterencoding=utf8&rvertimezone=gmt%2b8&ussl=fal urname: 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: lect 1 from dual test-while-idle: true test-on-borrow: true test-on-return: fal # 是否缓存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/*" ssion-stat-enable: true ssion-stat-max-count: 100 stat-view-rvlet: enabled: true url-pattern: /druid/* ret-enable: true #设置监控页面的登录名和密码 login-urname: admin login-password: admin allow: 127.0.0.1 mybatis: mapper-locations: classpath*:mapper/*.xml type-alias-package: com.zking.quartz02.model
1.导入quartz依赖
<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依赖。
<dependency><groupid>com.alibaba</groupid><artifactid>druid-spring-boot-starter</artifactid><version>1.1.10</version></dependency>
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.stdjdbcdelegateorg.quartz.jobstore.uproperties:falorg.quartz.jobstore.datasource:qzds#org.quartz.datasource.qzds.connectionprovider.class:org.quartz.utils.poolingconnectionproviderorg.quartz.datasource.qzds.connectionprovider.class:com.zking.q03.quartz.druidconnectionproviderorg.quartz.datasource.qzds.driver:com.mysql.jdbc.driverorg.quartz.datasource.qzds.url:jdbc:mysql://127.0.0.1:3306/test?uunicode=true&characterencoding=utf-8org.quartz.datasource.qzds.ur:rootorg.quartz.datasource.qzds.password:rootorg.quartz.datasource.qzds.maxconnections:30org.quartz.datasource.qzds.validationquery: lect 0*/ /** * [druid连接池的quartz扩展类] */public class druidconnectionprovider implements connectionprovider { /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * 常量配置,与quartz.properties文件的key保持一致(去掉前缀),同时提供t方法,quartz框架自动注入值。 * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ //jdbc驱动 public string driver; //jdbc连接串 public string url; //数据库用户名 public string ur; //数据库用户密码 public string password; //数据库最大连接数 public int maxconnection; //数据库sql查询每次连接返回执行到连接池,以确保它仍然是有效的。 publi笛声何处c string validationquery; private boolean validateoncheckout; private int idleconnectionvalidationconds; public string maxcachedstatementsperconnection; private string discardidleconnectionsconds; 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.clo(); } 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.tdriverclassname(this.driver); } catch (exception e) { try { throw new schedulerexception("problem tting driver class name on datasource: " + e.getmessage(), e); } catch (schedulerexception e1) { } } datasource.turl(this.url); datasource.turname(this.ur); datasource.tpassword(this.password); datasource.tmaxactive(this.maxconnection); datasource.tminidle(1); datasource.tmaxwait(0); datasource.tmaxpoolpreparedstatementperconnectionsize(this.default_db_max_cached_statements_per_connection); if (this.validationquery != null) { datasource.tvalidationquery(this.validationquery); if(!this.validateoncheckout) datasource.ttestonreturn(true); el datasource.ttestonborrow(true); datasource.tvalidationquerytimeout(this.idleconnectionvalidationconds); } } /* * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * 提供get t方法 * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ public string getdriver() { return driver; } public void tdriver(string driver) { this.driver = driver; } public string geturl() { return url; } public void turl(string url) { this.url = url; } public string getur() { return ur; } public void tur(string ur) { this.ur = ur; } public string getpassword() { return password; } public void tpassword(string password) { this.password = password; } public int getmaxconnection() { return maxconnection; } public void tmaxconnection(int maxconnection) { this.maxconnection = maxconnection; } public string getvalidationquery() { return validationquery; } public void tvalidationquery(string validationquery) { this.validationquery = validationquery; } public boolean isvalidateoncheckout() { return validateoncheckout; } public void tvalidateoncheckout(boolean validateoncheckout) { this.validateoncheckout = validateoncheckout; } public int getidleconnectionvalidationconds() { return idleconnectionvalidationconds; } public void t热爱祖国的诗idleconnectionvalidationconds(int idleconnectionvalidationconds) { this.idleconnectionvalidationconds = idleconnectionvalidationconds; } public druiddatasource getdatasource() { return datasource; } public void tdatasource(druiddatasource datasource) { this.datasource = datasource; }}
##============================================================================# configure main scheduler properties \u8c03\u5ea6\u5668\u5c5e\u6027#============================================================================org.quartz.scheduler.instancename: defaultquartzschedulerorg.quartz.scheduler.instanceid = autoorg.quartz.scheduler.rmi.export: falorg.quartz.scheduler.rmi.proxy: falorg.quartz.scheduler.wrapjobexecutioninurtransaction: falorg.quartz.threadpool.class: org.quartz.simpl.simplethreadpoolorg.quartz.threadpool.threadcount= 10org.quartz.threadpool.threadpriority: 5org.quartz.threadpool.threadsinheritcontextclassloaderofinitializingthread: trueorg.quartz.jobstore.misfirethreshold: 60000#============================================================================# configure jobstore#============================================================================#\u5b58\u50a8\u65b9\u5f0f\u4f7f\u7528jobstoretx\uff0c\u4e5f\u5c31\u662f\u6570\u636e\u5e93org.quartz.jobstore.class: org.quartz.impl.jdbcjobstore.jobstoretxorg.quartz.jobstore.driverdelegateclass:org.quartz.impl.jdbcjobstore.stdjdbcdelegate#\u4f7f\u7528\u81ea\u5df1\u7684\u914d\u7f6e\u6587\u4ef6org.quartz.jobstore.uproperties:true#\u6570\u636e\u5e93\u4e2dquartz\u8868\u7684\u8868\u540d\u524d\u7f00org.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\uff09org.quartz.jobstore.isclustered = true#============================================================================# configure datasources#============================================================================#\u914d\u7f6e\u6570\u636e\u5e9mick jagger3\u6e90org.quartz.datasource.qzds.connectionprovider.class: com.zking.quartz02.utils.druidconnectionproviderorg.quartz.datasource.qzds.driver: com.mysql.cj.jdbc.driver#修改为自己的数据库名称、用户名和密码org.quartz.datasource.qzds.url: jdbc:mysql://localhost:3306/quartz?uunicode=true&characterencoding=utf8&rvertimezone=gmt%2b8&ussl=falorg.quartz.datasource.qzds.ur: rootorg.quartz.datasource.qzds.password: 123org.quartz.datasource.qzds.maxconnection: 10
在数据库中创建quartz相关的表
进入quartz的官网http://www.quartz-scheduler.org/,点击downloads,
下载后在目录\docs\dbtables下有常用数据库创建quartz表的脚本,例如:“tables_mysql.sql”
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的问题@componentpublic 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; }}
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; @configurationpublic 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.tquartzproperties(this.getproperties()); //3.设置自定义的myjobfactory sc.tjobfactory(myjobfactory); return sc; } //读取配置文件 @bean public properties getproperties(){ try { propertiesfactorybean propertiesfactorybean = new propertiesfactorybean(); //设置自定义配置文件位置 propertiesfactorybean.tlocation(new classpathresource("/quartz.properties")); //读取配置文件 propertiesfactorybean.afterpropertiest(); 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语句即可)
-- 注意: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, --2018放假 外键:引用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传参
首先我们将t_schedule_trigger和t_schedule_trigger_param通过generatorconfig.xml自动生成实体类,xxmapper.java,xxmapper.xml.
<?xml version="1.0" encoding="utf-8" ?><!doctype generatorconfiguration public "-//mybatis.org//dtd mybatis generator configuration 1.0//en" "/d/file/titlepic/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\.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?uunicode=true&characterencoding=utf-8" urid="root" password="123"/> <!-- 类型转换 --> <javatyperesolver> <!-- 是否使用bigdecimal, fal可自动转化以下类型(long, integer, short, etc.) --> <property name="forcebigdecimals" value="fal"/> </javatyperesolver> <!-- 01 指定javabean生成的位置 --> <!-- targetpackage:指定生成的model生成所在的包名 --> <!-- targetproject:指定在该项目下所在的路径 --> <javamodelgenerator targetpackage="com.zking.quartz02.model" targetproject="src/main/java"> <!-- 是否允许子包,即targetpackage.schemaname.tablename --> <property name="enablesubpackages" value="fal"/> <!-- 是否对model添加构造函数 --> <property name="constructorbad" value="true"/> <!-- 是否针对string类型的字段在t的时候进行trim调用 --> <property name="trimstrings" value="fal"/> <!-- 建立的model对象是否 不可改变 即生成的model对象不会有 tter方法,只有构造方法 --> <property name="immutable" value="fal"/> </javamodelgenerator> <!-- 02 指定sql映射文件生成的位置 --> <sqlmapgenerator targetpackage="mapper" targetproject="src/main/resources"> <!-- 是否允许子包,即targetpackage.schemaname.tablename --> <property name="enablesubpackages" value="fal"/> </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,fal路径com.oop.eksp.ur.model, true:com.oop.eksp.ur.model.[schemaname] --> <property name="enablesubpackages" value="fal"/> </javaclientgenerator> <!-- 配置表信息 --> <!-- schema即为数据库名 --> <!-- tablename为对应的数据库表 --> <!-- domainobjectname是要生成的实体类 --> <!-- enable*byexample是否生成 example类 --> <!--<table schema="" tablename="t_book" domainobjectname="book"--> <!--enablecountbyexample="fal" enabledeletebyexample="fal"--> <!--enablelectbyexample="fal" enableupdatebyexample="fal">--> <!--<!– 忽略列,不生成bean 字段 –>--> <!--<!– <ignorecolumn column="fred" /> –>--> <!--<!– 指定列的java数据类型 –>--> <!--<!– <columnoverride column="long_varchar_field" jdbctype="varchar" /> –>--> <!--</table>--> <table schema="" tablename="t_schedule_trigger_param" domainobjectname="scheduletriggerparam" enablecountbyexample="fal" enabledeletebyexample="fal" enablelectbyexample="fal" enableupdatebyexample="fal"> <!-- 忽略列,不生成bean 字段 --> <!-- <ignorecolumn column="fred" /> --> <!-- 指定列的java数据类型 --> <!-- <columnoverride column="long_varchar_field" jdbctype="varchar" /> --> </table> <table schema="" tablename="t_schedule_trigger" domainobjectname="scheduletrigger" enablecountbyexample="fal" enabledeletebyexample="fal" enablelectbyexample="fal" enableupdatebyexample="fal"> <!-- 忽略列,不生成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自己需要写一个查询全部的方法。
写一个ischedulervice接口,用来定时刷新任务,更新调度器中的任务
package com.zking.quartz02.rvice; public interface ischedulervice { //定时刷新任务,更新调度器中的任务 public void refresh();}
实现ischedulervice接尿结石治疗口
package com.zking.quartz02.rvice.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.rvice.ischedulervice;import org.quartz.*;import org.springframework.scheduling.annotation.scheduled;import org.springframework.stereotype.rvice; import javax.annotation.resource;import java.util.list; @rvicepublic class schedulerviceimpl implements ischedulervice { @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); }el{//如果不为空,表示调度器中存在该任务 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) rvice层实现类使用@scheduled注解声明一个方法用于定时刷新数据库中的调度任务;
2) 使用@resource注解注入scheduler,在第5点中已装配到spring上下文;
3) 在启动类上加入@mapperscan(指定要变成实现类的接口所在的包路径,比如我的就是com.zking.quartz02.mapper),然后包下面的所有接口在编译之后都会生成相应的实现类;
4) 在启动类上加入@enablescheduling启动spring自带定时器任务;
要搞清楚一个问题:从数据库读取任务信息动态生成定时任务,和把quartz持久化到数据库是没有关系的。
前者是我们自己定义的业务表,而后者是quartz使用自己的表来存储信息。持久化到数据库后,
就算服务器重启或是多个quartz节点也没关系,因为他们共享数据库中的任务信息。
到此这篇关于springboot结合quartz实现数据库存储的文章就介绍到这了,更多相关springboot quartz数据库存储内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!
本文发布于:2023-04-04 15:49:27,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/2f5242a357cf0967475d4522746d287f.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:SpringBoot结合Quartz实现数据库存储.doc
本文 PDF 下载地址:SpringBoot结合Quartz实现数据库存储.pdf
留言与评论(共有 0 条评论) |