参考链接:
https://blog.csdn.net/wangmx1993328/article/details/105441308
https://blog.csdn.net/qq_39669058/article/details/90411497

参数配置连接:https://github.com/wangmaoxiong/quartzjdbc/blob/master/src/main/resources/application-cluster.yml

factory.setWaitForJobsToCompleteOnShutdown(true);
确认这个配置集群需要配置吗?
false

开源项目若依定时任务配置

package com.ruoyi.quartz.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.sql.DataSource;
import java.util.Properties;/*** 定时任务配置* * @author ruoyi*/
@Configuration
public class ScheduleConfig
{@Beanpublic SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource){SchedulerFactoryBean factory = new SchedulerFactoryBean();factory.setDataSource(dataSource);// quartz参数Properties prop = new Properties();//实例名称可以自定义prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");prop.put("org.quartz.scheduler.instanceId", "AUTO");// 线程池配置prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");prop.put("org.quartz.threadPool.threadCount", "20");prop.put("org.quartz.threadPool.threadPriority", "5");// JobStore配置prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");// 集群配置prop.put("org.quartz.jobStore.isClustered", "true");prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "false");// sqlserver 启用prop.put("org.quartz.jobStore.misfireThreshold", "12000");prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");factory.setQuartzProperties(prop);//实例名称可以自定义factory.setSchedulerName("RuoyiScheduler");// 延时启动factory.setStartupDelay(1);factory.setApplicationContextSchedulerContextKey("applicationContextKey");// 可选,QuartzScheduler// 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了factory.setOverwriteExistingJobs(true);factory.setWaitForJobsToCompleteOnShutdown(true);// 设置自动启动,默认为truefactory.setAutoStartup(true);return factory;}
}

一句话概括Quartz:

Quart分布式调度任务是通过数据库实现的,抢占式调度,一个任务只能在一个节点上执行,他的集群也仅仅是解决了单点故障(任务级别),实现了高可用,多个任务在集群中负载均衡调度,并没有解决任务分片的问题,不能实现水平扩展,如果执行大量的短任务,各个节点频繁的竞争数据库锁,节点越多这种情况越严重,性能会很低下。

版本为:SpringBoot 2.x,Quartz 2.3.0,Durid 1.1.9

这里不再使用c3p0数据源,在boot2.x中spring-boot-starter-quartz依赖默认是不依赖c3p0数据源的,如果要使用需要自己单独引用c3p0数据源,在quartz.properties配置下就可以了,这里使用的Druid数据源。

首先引入依赖:

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.43</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.9</version></dependency>

Druid-spring-boot-starter:
https://github.com/alibaba/druid/tree/master/druid-spring-boot-starter

application.yml文件配置,这里面配置的Druid数据源相关的,没有配置其他的,很单纯的

server:port: 8080
spring:application:name: quartzdatasource:url: jdbc:mysql://192.168.184.135:3306/quartzdb?characterEncoding=utf-8&useUnicode=true&useSSL=falsedriver-class-name: com.mysql.jdbc.Driver  # mysql8.0以前使用com.mysql.jdbc.Driverusername: rootpassword: 123456platform: mysql#通过这句配置将druid连接池引入到我们的配置中,spring会尽可能判断类型是什么,然后根据情况去匹配驱动类。type: com.alibaba.druid.pool.DruidDataSourcedruid:initial-size: 5  # 初始化大小min-idle: 5  # 最小max-active: 100  # 最大max-wait: 60000  # 配置获取连接等待超时的时间time-between-eviction-runs-millis: 60000  # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒min-evictable-idle-time-millis: 300000  # 指定一个空闲连接最少空闲多久后可被清除,单位是毫秒validationQuery: select 'x'test-while-idle: true  # 当连接空闲时,是否执行连接测试test-on-borrow: false  # 当从连接池借用连接时,是否测试该连接test-on-return: false  # 在连接归还到连接池时是否测试该连接filters: config,wall,stat  # 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙poolPreparedStatements: true # 打开PSCache,并且指定每个连接上PSCache的大小maxPoolPreparedStatementPerConnectionSize: 20maxOpenPreparedStatements: 20# 通过connectProperties属性来打开mergeSql功能;慢SQL记录connectionProperties: druid.stat.slowSqlMillis=200;druid.stat.logSlowSql=true;config.decrypt=false# 合并多个DruidDataSource的监控数据#use-global-data-source-stat: true#WebStatFilter配置,说明请参考Druid Wiki,配置_配置WebStatFilterweb-stat-filter:enabled: true #是否启用StatFilter默认值trueurl-pattern: /*exclusions: /druid/*,*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.icosession-stat-enable: truesession-stat-max-count: 10#StatViewServlet配置,说明请参考Druid Wiki,配置_StatViewServlet配置stat-view-servlet:enabled: true #是否启用StatViewServlet默认值trueurl-pattern: /druid/*reset-enable: truelogin-username: adminlogin-password: admin

quartz.properties配置文件

#调度标识名 集群中每一个实例都必须使用相同的名称
org.quartz.scheduler.instanceName = quartzScheduler
#调度器实例编号自动生成,每个实例不能不能相同
org.quartz.scheduler.instanceId = AUTO
#开启分布式部署,集群
org.quartz.jobStore.isClustered = true
#分布式节点有效性检查时间间隔,单位:毫秒,默认值是15000
org.quartz.jobStore.clusterCheckinInterval = 2000
#远程管理相关的配置,全部关闭
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
#实例化ThreadPool时,使用的线程类为SimpleThreadPool(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
##并发个数,指定线程数,至少为1(无默认值)(一般设置为1-100之间的的整数合适)
org.quartz.threadPool.threadCount = 10
##设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
org.quartz.threadPool.threadPriority = 5
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
#容许的最大作业延长时间,最大能忍受的触发超时时间,如果超过则认为“失误”,不敢再内存中还是数据中都要配置
org.quartz.jobStore.misfireThreshold = 6000
#持久化方式配置
# 默认存储在内存中,保存job和Trigger的状态信息到内存中的类
#org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
#数据库方式
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#持久化方式配置数据驱动,MySQL数据库
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#quartz相关数据表前缀名
org.quartz.jobStore.tablePrefix = QRTZ_#数据库别名 随便取
#org.quartz.jobStore.dataSource = qzDS
#org.quartz.dataSource.qzDS.driver = com.mysql.jdbc.Driver
#org.quartz.dataSource.qzDS.URL = jdbc:mysql://192.168.184.135:3306/quartzdb?useSSL=false&useUnicode=true&characterEncoding=UTF-8
#org.quartz.dataSource.qzDS.user = root
#org.quartz.dataSource.qzDS.password = 123456
#org.quartz.dataSource.qzDS.maxConnections = 10
#org.quartz.dataSource.qzDS.acquireIncrement=1

///分割一下///

我这里使用的是MySql数据库,想要使用Oracle数据库,导入表(@"/路径/tables_oracle.sql"),不管你怎么导,只要能用就行,在数据源的地方修改下连接信息,修改quartz.properties文件修改为如下,直接启动就行了

org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate


///分割一下///

案例结构

模拟任务调度service层的业务逻辑

UserService.java

package com.quartz.service;import java.io.Serializable;public interface UserService extends Serializable {void getUserInfo();void getUserAddr();
}

UserServiceImpl.java

package com.quartz.service.impl;import com.quartz.service.UserService;
import org.springframework.stereotype.Service;@Service
public class UserServiceImpl implements UserService {@Overridepublic void getUserInfo() {System.err.println("调度getUserInof成功");}@Overridepublic void getUserAddr() {System.err.println("调度getUserAddr成功");}
}

任务

JobOne.java

package com.quartz.job;import com.quartz.service.UserService;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;@Component
@DisallowConcurrentExecution //保证上一次任务执行完毕再执行下一任务
//@PersistJobDataAfterExecution //上一个任务完成前写入需要被下一个任务获取的变量以及对应的属性值,类似求和累加
public class JobOne extends QuartzJobBean {private UserService userService;@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {userService.getUserInfo();}public void setUserService(UserService userService) {this.userService = userService;}
}

JobTwo.java

package com.quartz.job;import com.quartz.service.UserService;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;@Component
@DisallowConcurrentExecution
public class JobTwo extends QuartzJobBean {//不能使用注入的方式,只能使用DateMap方式传入参数private UserService userService;@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {userService.getUserAddr();}public void setUserService(UserService userService) {this.userService = userService;}
}

JobConfig.java

package com.quartz.jobconfig;import com.quartz.job.JobOne;
import com.quartz.job.JobTwo;
import com.quartz.service.UserService;
import org.quartz.JobDataMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;@Configuration
public class JobConfig {@Autowiredprivate UserService userService;@Bean("jobOneDetail")public JobDetailFactoryBean jobOneDetailFactoryBean(JobOne jobOne) {JobDetailFactoryBean jobDetailFactoryBean =new JobDetailFactoryBean();jobDetailFactoryBean.setJobClass(jobOne.getClass());//没有绑定触发器仍然保留在Quartz的JobStore中jobDetailFactoryBean.setDurability(true);jobDetailFactoryBean.setName("jobOneDetailName");jobDetailFactoryBean.setGroup("jobOneDetailGroup");JobDataMap jobDataMap = new JobDataMap ();jobDataMap.put ("userService",userService);jobDetailFactoryBean.setJobDataMap(jobDataMap) ;return jobDetailFactoryBean;}@Bean("jobOneTrigger")public CronTriggerFactoryBean cronTriggerOneFactoryBean(@Qualifier("jobOneDetail") JobDetailFactoryBean jobDetailFactoryBean){CronTriggerFactoryBean cronTriggerFactoryBean=new CronTriggerFactoryBean();cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());cronTriggerFactoryBean.setCronExpression("*/1 * * * * ?");cronTriggerFactoryBean.setName("jobOneTriggerName");cronTriggerFactoryBean.setGroup("jobOneTriggerGroup");return cronTriggerFactoryBean;}@Bean("jobTwoDetail")public JobDetailFactoryBean jobTwoDetailFactoryBean(JobTwo jobTwo) {JobDetailFactoryBean jobDetailFactoryBean =new JobDetailFactoryBean();jobDetailFactoryBean.setJobClass(jobTwo.getClass());jobDetailFactoryBean.setDurability(true);jobDetailFactoryBean.setName("jobTwoDetailName");jobDetailFactoryBean.setGroup("jobTwoDetailGroup");JobDataMap jobDataMap = new JobDataMap ();jobDataMap.put ("userService",userService);jobDetailFactoryBean.setJobDataMap(jobDataMap) ;return jobDetailFactoryBean;}@Bean("jobTwoTrigger")public CronTriggerFactoryBean cronTriggerTwoFactoryBean(@Qualifier("jobTwoDetail") JobDetailFactoryBean jobDetailFactoryBean){CronTriggerFactoryBean cronTriggerFactoryBean=new CronTriggerFactoryBean();cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());cronTriggerFactoryBean.setCronExpression("*/1 * * * * ?");cronTriggerFactoryBean.setName("jobTwoTriggerName");cronTriggerFactoryBean.setGroup("jobTwoTriggerGroup");return cronTriggerFactoryBean;}}

SchedulerConfig.java

package com.quartz.jobconfig;import com.alibaba.druid.pool.DruidDataSource;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;@Configuration
public class SchedulerConfig {//执行任务。有了触发器,我们就可以执行任务了。注册一个SchedulerFactroyBean,然后将触发器一list的方式传入@Beanpublic SchedulerFactoryBean schedulerFactoryBean(DruidDataSource druidDataSource, @Qualifier("jobOneTrigger") Trigger jobOneTrigger, @Qualifier("jobTwoTrigger") Trigger jobTwoTrigger){SchedulerFactoryBean schedulerFactoryBean=new SchedulerFactoryBean();//调度器名称schedulerFactoryBean.setSchedulerName("TestScheduler");//数据源schedulerFactoryBean.setDataSource(druidDataSource);//覆盖已存在的任务,用于Quartz集群,QuartzScheduler启动会更新已存在的JobschedulerFactoryBean.setOverwriteExistingJobs(true);//延时1s启动定时任务,避免系统未完全启动却开始执行定时任务的情况schedulerFactoryBean.setStartupDelay(1);//设置加载的quartz.properties配置文件schedulerFactoryBean.setConfigLocation(new ClassPathResource("/quartz.properties"));//自动启动schedulerFactoryBean.setAutoStartup(true);//注册触发器schedulerFactoryBean.setTriggers(jobOneTrigger,jobTwoTrigger);return schedulerFactoryBean;}
}

启动两个改下端口8080,8081就行了,看到效负载调度。

节点争抢Job问题

因为Quartz使用了一个随机的负载均衡算法, Job以随机的方式由不同的实例执行。Quartz官网上提到当前,还不存在一个方法来指派(钉住) 一个 Job 到集群中特定的节点。

参考链接:https://blog.csdn.net/qq_39669058/article/details/90411497

Springboot整合Quartz集群部署以及配置Druid数据源相关推荐

  1. Spring整合Quartz集群部署

    Spring整合Quartz集群部署 Quartz的分布式模式 数据表创建 quartz.properties spring-job.xml Quartz的分布式模式 集群中的每个节点都是一个独立的Q ...

  2. 搭建第一个SpringBoot工程;SpringBoot整合mybatis;SpringBoot整合Redis-cluster集群;SpringBoot整合EhCache;

    写在前头,以下内容主要是为了自己复习之用,如果你有幸看到这篇文章,请不要嫌弃某些地方有所跳跃或省略. 1. 搭建第一个SpringBoot工程 1.1 创建工程 1.2 初始pom.xml文件内容 1 ...

  3. java集群解析文件_java相关:springboot整合redis集群过程解析

    java相关:springboot整合redis集群过程解析 发布于 2020-4-13| 复制链接 摘记: 简介 在springboot使用搭建好的redis集群添加redis和连接池依赖 ```x ...

  4. 七、SpringBoot整合elasticsearch集群

    @Author : By Runsen @Date : 2020/6/12 作者介绍:Runsen目前大三下学期,专业化学工程与工艺,大学沉迷日语,Python, Java和一系列数据分析软件.导致翘 ...

  5. SpringBoot整合Redis集群版本问题

    QUESTION:SpringBoot整合Redis集群版本问题? ANSWER: 版本依赖: <dependencies><!-- https://mvnrepository.co ...

  6. rabbitmq集群部署及配置

    rabbitmq集群部署及配置 文章目录 rabbitmq集群部署及配置 前言 一.原理介绍 二.部署方案 1.环境介绍 2.部署过程 小结 前言 消息中间件rabbitmq,一般以集群方式部署,主要 ...

  7. springboot篇】二十二. springboot整合Redis集群

    springboot整合Redis集群 **中国加油,武汉加油!** 案例准备 1. 新建Springboot项目springboot-redis-sentinel 2. 编写yml 3. Test ...

  8. Linux中级实战专题篇:rabbitmq(消息中间件p2p模式和pub模式,消息队列rabbitmq详解,单机安装,集群部署以及配置实战)

    一.消息中间件相关概念 1.简介 消息中间件也可以称消息队列,是指用高效可靠的消息传递机制进行与平台相关 的数据交流,并基于数据通信来进行分布式系统的集成.通过提供消息传递和消息 队列模型,可以在分布 ...

  9. springBoot整合redis集群配置

    最近发现这篇博客阅读量比较大,今天特意抽空创建了一个可运行的开源项目. 项目的代码和之前的博客内容相比,做了些优化,请大家参考项目源码. 开源项目源码: springboot-redis-cluste ...

最新文章

  1. 关于git的使用记录总结
  2. .net 导出excel和word
  3. python详细安装教程环境配置-python环境配置详细步骤
  4. html应用中心模板,HTML5--应用网页模板
  5. python文本框清空_用Python制作mini翻译器
  6. 在OpenShift上将JMS与JBoss A-MQ结合使用。 从远程客户端和加密中学到的经验教训。...
  7. 8大原则带你秒懂Happens-Before原则
  8. android基础知识学习(1) TextView属性大全+单行显示长文本
  9. qt lineedit获取内容_Qt开发中的几个关键知识点,收藏以备参考
  10. drawforeground只有鼠标事件进入才刷新_罗技各系鼠标测评(2020年12月更新)
  11. 【纪中集训2019.3.25】礼物
  12. css的9个常用选择器
  13. GridView控件 Reapter控件 DataList控件 的区别和用法
  14. python下载及安装教程
  15. 【NCRE】---拼接SQL语句(Case....When语句)
  16. 分享两篇适合程序员看的书籍——《谁动了我的奶酪》、《你的灯亮着吗?》读后感
  17. c语言常用函数库 c++常用函数库
  18. java编程个人总结_java个人总结
  19. 一键自动AI抠图,堪比人工PS!
  20. cmd命令,最新的装逼利器

热门文章

  1. AI算法连载14:统计之模型选择
  2. 清华90后博士后万蕊雪:科研这场马拉松,我会一直跑下去
  3. 约翰·格伦:77岁宇航员的传奇一生
  4. 二维码提升对比度文献调研(3)--A Low-Complexity Algorithm for Contrast Enhancement of Digital Images
  5. python文件操作以及相对路径和绝对路径问题
  6. Cloudera-Manager 与 原生集群 免密登录问题
  7. 储留香:一个智能运维系统就是一个中枢神经系统,我说的!
  8. 如何将实时计算 Flink 与自身环境打通
  9. 云数据库RDS基础版的优势及适用场景
  10. 重磅!阿里云发布最新服务等级协议SLA ,多实例可用性升为99.995%