Spring+Quartz框架实现定时任务(集群,分布式)

1、定时任务的必要性:

定时任务在应用中的重要性不言而喻,大多是应用,特别是金融应用更是离不开定时任务,能用定时任务来处理异常订单,完成跑批,定时活动(双11)等。
在初期应用的访问量并不是那么大,一台服务器完全满足使用,但是随着用户量、业务量的逐日增加,应用中会有很多定时任务需要执行,一台服务器已经不能满足使用,
因此需要把应用给部署到集群中,前端通过nginx代理实现访问。

2、集群使用定时任务的问题:
目前大部分在集群中处理定时任务的方式不是正真的分布式处理方式,而是一种伪分布式,这种方式存在一个明显的缺陷就是当集群中机器宕机,
那么整个定时任务就会挂掉或者不能一次性跑完,会对业务产生严重的影响。

而且在集群环境中,同样的定时任务,在集群中的每台服务器都会执行,这样定时任务就会重复执行,不但会增加服务器的负担,还会因为定时任务重复执行造成额外的不可预期的错误。
解决方案是:
根据集群的数量,把定时任务中的任务平均分到集群中的每台机器上(这里的平均分是指以前多个定时任务本来是在一台机器上运行,先在人为的把这些任务分成几部分,让所有的机器分别去执行这些任务)
这就是采用了分布式定时任务来进行处理。
另外一种解决方式:
使用Quartz框架,在集群环境下,通过数据库锁机制来实现定时任务的执行,下面会介绍。

3、Quartz介绍:

Quartz是一个开放源码项目,专注于任务调度器,提供了极为广泛的特性如持久化任务,集群和分布式任务等。 
Quartz核心是调度器,还采用多线程管理。quartz框架是原生就支持分布式定时任务的。

1.持久化任务(把调度信息存储到数据):当应用程序停止运行时,所有调度信息不被丢失,当你重新启动时,调度信息还存在,这就是持久化任务。
 
2.集群和分布式处理:当在集群环境下,当有配置Quartz的多个客户端时(节点),
采用Quartz的集群和分布式处理时,我们要了解几点好处 
1) 一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。
2) Quartz调度是通过触发器的类别来识别不同的任务,在不同的节点定义相同的触发器的类别,这样在集群下能稳定的运行,一个节点无法完成的任务,会被集群中拥有相同的任务的节点取代执行。
3)分布式 体现在 当相同的任务定时在一个时间点,在那个时间点,不会被两个节点同时执行。

4、Quartz 在集群如何工作:


一个 Quartz 集群中的每个节点是一个独立的 Quartz 应用,你必须对每个节点分别启动或停止。
大多数应用服务器的集群,独立的 Quartz 节点并不与另一其的节点或是管理节点通信,彼此相互独立。
Quartz 应用是通过数据库表来感知到另一应用的,调度信息存储在数据库中,当集群定时任务操作数据库(读取任务信息,更新任务信息)
数据库就会被加锁,防止其他相同的任务也读取到该任务,避免任务的重复执行。

5、环境搭建-创建Quartz数据库表

因为Quartz 集群依赖于数据库,所以必须首先创建Quartz数据库表。
Quartz 包括了所有被支持的数据库平台的 SQL 脚本。在 <quartz_home>/docs/dbTables 目录下找到那些 SQL 脚本,这里的 <quartz_home> 是解压 Quartz 分发包后的目录。
Quartz 2.2.3版本,总共11张表,不同版本,表个数可能不同。数据库为mysql,用tables_mysql_innodb.sql创建数据库表,数据库不同选择的建表sql也不同,根据自己选择。

6、环境搭建-配置 Quartz 使用集群

1.配置节点的 quartz.properties 文件

# Configure Main Scheduler Properties
# Needed to manage cluster instances
org.quartz.scheduler.instanceName = TestScheduler1   
org.quartz.scheduler.instanceId = AUTO

# Configure ThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

# Configure JobStore
# Using Spring datasource in quartzJobsConfig.xml
# Spring uses LocalDataSourceJobStore extension of JobStoreCMT
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.maxMisfiresToHandleAtATime=10
org.quartz.jobStore.isClustered = true  
org.quartz.jobStore.clusterCheckinInterval = 20000

org.quartz.scheduler.instanceName:
属性可为任何值,用在 JDBC JobStore 中来唯一标识实例,但是所有集群节点中必须相同。

org.quartz.scheduler.instanceId:
属性为 AUTO即可,基于主机名和时间戳来产生实例 ID。

org.quartz.jobStore.class:
属性为 JobStoreTX,将任务持久化到数据中。因为集群中节点依赖于数据库来传播 Scheduler 实例的状态,你只能在使用 JDBC JobStore 时应用 Quartz 集群。
这意味着你必须使用 JobStoreTX 或是 JobStoreCMT 作为 Job 存储;你不能在集群中使用 RAMJobStore。

org.quartz.jobStore.isClustered: 
属性为 true,你就告诉了 Scheduler 实例要它参与到一个集群当中。
这一属性会贯穿于调度框架的始终,用于修改集群环境中操作的默认行为。

org.quartz.jobStore.clusterCheckinInterval:
属性定义了Scheduler 实例检入到数据库中的频率(单位:毫秒)。
Scheduler 检查是否其他的实例到了它们应当检入的时候未检入;这能指出一个失败的 Scheduler 实例,且当前 Scheduler 会以此来接管任何执行失败并可恢复的 Job。
通过检入操作,Scheduler 也会更新自身的状态记录。clusterChedkinInterval 越小,Scheduler 节点检查失败的 Scheduler 实例就越频繁。默认值是 15000 (即15 秒)。

7、配置applicationContext-quartz.xml文件,在这里配置任务,数据库连接等

[html] view plain copy

  1. <span style="font-size:14px;"><beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" </span>

[html] view plain copy

  1. <span style="font-size:14px;"><span style="white-space:pre">        </span>xmlns:context="http://www.springframework.org/schema/context"
  2. xsi:schemaLocation="http://www.springframework.org/schema/beans
  3. http://www.springframework.org/schema/beans/spring-beans-4.0.xsd </span>

[html] view plain copy

  1. <span style="font-size:14px;"><span style="white-space:pre">        </span>http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  2. <!-- 配置扫描的包 -->
  3. <context:component-scan base-package="com.clusterquartz.job" />
  4. <!-- JNDI连接数据库 -->
  5. <bean name="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
  6. <!-- tomcat -->
  7. <!--<property name="jndiName" value="java:comp/env/jndi/mysql/quartz"/> -->
  8. <!-- jboss -->
  9. <property name="jndiName" value="jdbc/quartz" />
  10. </bean>
  11. <!-- 分布式事务配置 start -->
  12. <!-- 配置线程池 -->
  13. <bean name="executor"
  14. class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
  15. <property name="corePoolSize" value="15" />
  16. <property name="maxPoolSize" value="25" />
  17. <property name="queueCapacity" value="100" />
  18. </bean>
  19. <!-- 配置事务管理器 -->
  20. <bean name="transactionManager"
  21. class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  22. <property name="dataSource" ref="dataSource" />
  23. </bean>
  24. <!-- 配置调度任务 -->
  25. <bean name="quartzScheduler"
  26. class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  27. <property name="configLocation" value="classpath:quartz.properties" />
  28. <property name="dataSource" ref="dataSource" />
  29. <property name="transactionManager" ref="transactionManager" />
  30. <!-- 任务唯一的名称,将会持久化到数据库 -->
  31. <property name="schedulerName" value="baseScheduler" />
  32. <!-- 每台集群机器部署应用的时候会更新触发器 -->
  33. <property name="overwriteExistingJobs" value="true" />
  34. <property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
  35. <property name="jobFactory">
  36. <bean
  37. class="com.clusterquartz.autowired.AutowiringSpringBeanJobFactory" />
  38. </property>
  39. <property name="triggers">
  40. <list>
  41. <ref bean="printCurrentTimeScheduler" />
  42. </list>
  43. </property>
  44. <property name="jobDetails">
  45. <list>
  46. <ref bean="printCurrentTimeJobs" />
  47. </list>
  48. </property>
  49. <property name="taskExecutor" ref="executor" />
  50. </bean>
  51. <!-- 配置Job详情,job实现业务逻辑 -->
  52. <bean name="printCurrentTimeJobs"
  53. class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
  54. <property name="jobClass"
  55. value="com.clusterquartz.job.PrintCurrentTimeJobs" />
  56. <property name="durability" value="true" />
  57. <property name="requestsRecovery" value="true" />
  58. </bean>
  59. <!-- 配置触发时间 -->
  60. <bean name="printCurrentTimeScheduler"
  61. class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
  62. <property name="jobDetail" ref="printCurrentTimeJobs" />
  63. <property name="cronExpression">
  64. <value>0/2 * * * * ?</value>
  65. </property>
  66. </bean>
  67. <!-- 分布式事务配置 end -->
  68. <!-- 方式二:使用MethodInvokingJobDetailFactoryBean,任务类可以不实现Job接口,通过targetMethod指定调用方法 -->
  69. <!-- 定义目标bean和bean中的方法 -->
  70. <bean id="SpringQtzJob" class="com.clusterquartz.job.SpringQtz" />
  71. <bean id="SpringQtzJobMethod"
  72. class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
  73. <property name="targetObject">
  74. <ref bean="SpringQtzJob" />
  75. </property>
  76. <property name="targetMethod">  <!-- 要执行的方法名称 -->
  77. <value>execute</value>
  78. </property>
  79. </bean>
  80. <!-- 调度触发器 -->
  81. <bean name="printCurrentTimeScheduler"
  82. class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
  83. <property name="jobDetail" ref="SpringQtzJobMethod" />
  84. <property name="cronExpression">
  85. <value>0/10 * * * * ?</value>
  86. </property>
  87. </bean>
  88. </beans></span>

applicationContextSchedulerContextKey:
是org.springframework.scheduling.quartz.SchedulerFactoryBean这个类中把spring上下文以key/value的方式存放在了SchedulerContext中了,
可以用applicationContextSchedulerContextKey所定义的key得到对应spring 的ApplicationContext; 
会在后面的类里用到

configLocation:用于指明quartz的配置文件的位置

requestsRecovery:
属性必须设置为 true,当Quartz服务被中止后,再次启动或集群中其他机器接手任务时会尝试恢复执行之前未完成的所有任务。

8、介绍相关的类:

1、

[html] view plain copy

  1. <property name="jobFactory">
  2. <bean
  3. class="com.clusterquartz.autowired.AutowiringSpringBeanJobFactory" />
  4. </property>

这个类的作用:

[java] view plain copy

  1. <span style="font-size:14px;">/**
  2. * @author
  3. * @description 使我们的任务类支持Spring的自动注入
  4. */
  5. public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory
  6. implements ApplicationContextAware {
  7. private transient AutowireCapableBeanFactory beanFactory;
  8. public void setApplicationContext(ApplicationContext applicationContext)
  9. throws BeansException {
  10. beanFactory = applicationContext.getAutowireCapableBeanFactory();
  11. }
  12. @Override
  13. protected Object createJobInstance(TriggerFiredBundle bundle)
  14. throws Exception {
  15. Object job = super.createJobInstance(bundle);
  16. beanFactory.autowireBean(job);
  17. return job;
  18. }
  19. }</span>

调用我们任务类的实现:
/**
* @author
* @description 当前任务是每隔一定时间打印当前的时间
*/
public class PrintCurrentTimeJobs extends QuartzJobBean {
private static final Log LOG_RECORD = LogFactory
.getLog(PrintCurrentTimeJobs.class);
/*
* 这里就是因为有上文中的AutowiringSpringBeanJobFactory才可以使用像@Autowired的注解,当然还可以使用Spring的其他注解
* 否则只能在配置文件中设置这属性的值,另一种方式下面说到
*/
@Autowired
private ClusterQuartz clusterQuartz;

protected void executeInternal(JobExecutionContext jobExecutionContext)
throws JobExecutionException {
LOG_RECORD.info("begin to execute task,"
+ DateUtil.dateFmtToString(new Date()));
//我们真正要执行的任务
clusterQuartz.printUserInfo();

LOG_RECORD.info("end to execute task,"
+ DateUtil.dateFmtToString(new Date()));
}
}

我们定时任务的具体逻辑实现:(我们很熟悉的Spring,注解开发)
@Service("ClusterQuartz")
public class ClusterQuartz {
private static final Logger logger = LoggerFactory
.getLogger(ClusterQuartz.class);

/*在这里可以使用spring的注解,引入各种服务之类的*/

/*@Resource(name = "miService")
private MiService miService;

@Autowired
private PushServiceI pushRecordService;*/

public void printUserInfo() {
System.out.println("定时任务的实现逻辑代码");

}
}

2、如果不配置上面1的那个property,我们的定时任务这样实现:

[java] view plain copy

  1. <span style="white-space:pre">      </span><span style="font-size:14px;">//执行定时任务的类
  2. @PersistJobDataAfterExecution
  3. @DisallowConcurrentExecution
  4. // 不允许并发执行
  5. public class MyQuartzJobBean1 extends QuartzJobBean {
  6. private static final Logger logger = LoggerFactory
  7. .getLogger(MyQuartzJobBean1.class);
  8. @Override
  9. protected void executeInternal(JobExecutionContext jobexecutioncontext)
  10. throws JobExecutionException {
  11. SimpleService simpleService = getApplicationContext(jobexecutioncontext)
  12. .getBean("simpleService", SimpleService.class);
  13. //我们定时任务的方法
  14. simpleService.testMethod1();
  15. }
  16. private ApplicationContext getApplicationContext(
  17. final JobExecutionContext jobexecutioncontext) {
  18. try {
  19. //在这里用applicationContextSchedulerContextKey所定义的key得到对应spring 的ApplicationContext;
  20. return (ApplicationContext) jobexecutioncontext.getScheduler()
  21. .getContext().get("applicationContextKey");
  22. } catch (SchedulerException e) {
  23. logger.error(
  24. "jobexecutioncontext.getScheduler().getContext() error!", e);
  25. throw new RuntimeException(e);
  26. }
  27. }
  28. }
  29. 而定时任务的具体逻辑业务,还是和上面的一样。
  30. @Service("simpleService")
  31. public class SimpleService {
  32. private static final Logger logger = LoggerFactory.getLogger(SimpleService.class);
  33. public void testMethod1(){
  34. //这里执行定时调度业务
  35. logger.info("testMethod1.......1");
  36. System.out.println("2--testMethod1......."+System.currentTimeMillis()/1000);
  37. }
  38. public void testMethod2(){
  39. logger.info("testMethod2.......2");
  40. }
  41. }</span>

9、运行测试Quartz集群定时任务:

public class MainTest {
public static void main(String[] args) {
ApplicationContext springContext = new ClassPathXmlApplicationContext(
new String[] { "classpath:applicationContext.xml",
"classpath:applicationContext-quartz.xml" });
}

}

10、在Spring中使用Quartz有两种方式实现:

第一种是任务类继承QuartzJobBean,第二种则是在配置文件里定义任务类和要执行的方法,类和方法仍然是普通类。
很显然,第二种方式远比第一种方式来的灵活。我们发现上面采用的就是第一种方法,下面说下第二种方法。

1、配置XML如下:

<!-- 方式二:使用MethodInvokingJobDetailFactoryBean,任务类可以不实现Job接口,通过targetMethod指定调用方法 -->
<!-- 定义目标bean和bean中的方法 -->
<bean id="SpringQtzJob" class="com.clusterquartz.job.SpringQtz" />
<bean id="SpringQtzJobMethod"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="SpringQtzJob" />
</property>
<property name="targetMethod">  <!-- 要执行的方法名称 -->
<value>execute</value>
</property>
</bean>
<!-- 调度触发器 -->
<bean name="printCurrentTimeScheduler"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="SpringQtzJobMethod" />
<property name="cronExpression">
<value>0/10 * * * * ?</value>
</property>
</bean>

2、任务类:(普通的Java类)

public class SpringQtz {
private static int counter = 0;

protected void execute() {
long ms = System.currentTimeMillis();
System.out.println("\t\t" + new Date(ms));
System.out.println("(" + counter++ + ")");
}
}

11、Quartz版本问题:

spring3.1以下的版本必须使用quartz1.x系列,3.1以上的版本才支持quartz 2.x,不然会出错。
不匹配异常:
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.scheduling.quartz.CronTriggerBean] for bean with name ‘mytrigger‘ defined in class path resource [applicationContext.xml]: problem with class file or dependent class; nested exception is java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as super class 
异常原因:
spring3.0.5中org.springframework.scheduling.quartz.CronTriggerBean继承了org.quartz.CronTrigger(public class CronTriggerBeanextends CronTrigger),
而在quartz2.1.3中org.quartz.CronTrigger是个接口(publicabstract interface CronTrigger extends Trigger),
而在quartz1.8.5及1.8.4中org.quartz.CronTrigger是个类(publicclass CronTrigger extends Trigger),
从而造成无法在applicationContext中配置触发器。这是spring3.1以下版本和quartz2版本不兼容的一个bug。

12、关于cronExpression表达式,这里提一下: 
字段 允许值 允许的特殊字符 
秒 0-59 , - * / 
分 0-59 , - * / 
小时 0-23 , - * / 
日期 1-31 , - * ? / L W C 
月份 1-12 或者 JAN-DEC , - * / 
星期 1-7 或者 SUN-SAT , - * ? / L C # 
年(可选) 留空, 1970-2099 , - * / 
表达式意义 
"0 0 12 * * ?" 每天中午12点触发 
"0 15 10 ? * *" 每天上午10:15触发 
"0 15 10 * * ?" 每天上午10:15触发 
"0 15 10 * * ? *" 每天上午10:15触发 
"0 15 10 * * ? 2005" 2005年的每天上午10:15触发 
"0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发 
"0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 
"0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 
"0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 
"0 15 10 15 * ?" 每月15日上午10:15触发 
"0 15 10 L * ?" 每月最后一日的上午10:15触发 
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 
"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发 
每天早上6点 
0 6 * * * 
每两个小时 
0 */2 * * * 
晚上11点到早上8点之间每两个小时,早上八点 
0 23-7/2,8 * * * 
每个月的4号和每个礼拜的礼拜一到礼拜三的早上11点 
0 11 4 * 1-3 
1月1日早上4点 
0 4 1 1 *

13、一般applicationContext-quartz.xml的框架配置:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 任务调度配置 -->
<bean name="quartzScheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 配置数据库 -->
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="configLocation" value="classpath:quartz.properties" />
<property name="triggers">
<!-- 类似的可以在这里添加定时任务触发器 -->
<list>
<ref bean="trigger1" />
<ref bean="trigger2" />
</list>
</property>
</bean>

<!-- 任务具体工厂 -->
<bean id="jobDetail1"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 具体实现类,当然这里我们的class继承 QuartzJobBean了 -->
<property name="jobClass">
<value>com.sundoctor.quartz.cluster.example.MyQuartzJobBean1</value>
</property>
<property name="durability" value="true" />
<property name="requestsRecovery" value="true" />
</bean>
<!-- 配置触发器,包含执行时间,具体任务等 -->
<bean id="trigger1"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail1" />
<property name="cronExpression" value="0/10 * * * * ?" />
</bean>
</beans>

14、Quartz运行解释:

Quartz 实际并不关心你是在相同的还是不同的机器上运行节点。
当集群是放置在不同的机器上时,通常称之为水平集群。节点是跑在同一台机器是,称之为垂直集群。
对于垂直集群,存在着单点故障的问题。这对高可用性的应用来说是个坏消息,因为一旦机器崩溃了,所有的节点也就被有效的终止了。

当你运行水平集群时,时钟应当要同步,以免出现离奇且不可预知的行为。
假如时钟没能够同步,Scheduler 实例将对其他节点的状态产生混乱。
有几种简单的方法来保证时钟何持同步,而且也没有理由不这么做。最简单的同步计算机时钟的方式是使用某一个 Internet 时间服务器(Internet Time Server ITS)。

没什么会阻止你在相同环境中使用集群的和非集群的 Quartz 应用。
唯一要注意的是这两个环境不要混用在相同的数据库表。
意思是非集群环境不要使用与集群应用相同的一套数据库表;否则将得到希奇古怪的结果,集群和非集群的 Job 都会遇到问题。

假如你让一个非集群的 Quartz 应用与集群节点并行着运行,设法使用 JobInitializationPlugin和 RAMJobStore。

15、配置数据库连接,

1、通用的
<!-- 数据源定义,使用c3p0 连接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialPoolSize" value="2" />
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="20" />
<property name="acquireIncrement" value="2" />
<property name="maxIdleTime" value="1800" />
</bean>

2、JNDI连接数据库

<!-- JNDI连接数据库 -->
<bean name="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<!-- tomcat -->
<!--<property name="jndiName" value="java:comp/env/jndi/mysql/quartz"/> -->

<!-- jboss -->
<property name="jndiName" value="jdbc/quartz" />
</bean>

3、Druid连接池(公司用)

<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_username}" />
<property name="password" value="${jdbc_password}" />
<property name="initialSize" value="0" />
<property name="maxActive" value="20" />
<property name="maxIdle" value="50" />
<property name="minIdle" value="0" />
<property name="maxWait" value="60000" />
<property name="validationQuery" value="${validationQuery}" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<!-- 打开removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分钟 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 关闭abanded连接时输出错误日志 -->
<property name="logAbandoned" value="true" />
<!-- 打开PSCache,并且指定每个连接上PSCache的大小 如果用Oracle,则把poolPreparedStatements配置为true,mysql可以配置为false。 -->
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize"
value="20" />
<!-- 解密密码必须要配置的项 -->
<property name="filters" value="wall,stat,config" />
<property name="connectionProperties"
value="config.decrypt=true;config.decrypt.key=${jdbc_publickey}" />
</bean>

在我的资源里上传了上面实例的代码,有需要的支持下,有不当之处,望各位猿友之处,万分感谢。

相信您一定对定时任务又有了深刻的认识

每天努力一点,每天都在进步。

原文地址:https://www.cnblogs.com/luohero/p/8602306.html

时间: 2024-11-08 23:07:00

Spring+Quartz框架实现定时任务(集群,分布式)的相关文章

quartz集群分布式(并发)部署解决方案-Spring

项目中使用分布式并发部署定时任务,多台跨JVM,按照常理逻辑每个JVM的定时任务会各自运行,这样就会存在问题,多台分布式JVM机器的应用服务同时干活,一个是加重服务负担,另外一个是存在严重的逻辑问题,比如需要回滚的数据,就回滚了多次,刚好quartz提供很好的解决方案. 集群分布式并发环境中使用QUARTZ定时任务调度,会在各个节点会上报任务,存到数据库中,执行时会从数据库中取出触发器来执行,如果触发器的名称和执行时间相同,则只有一个节点去执行此任务. 如果此节点执行失败,则此任务则会被分派到另

Spring Cloud(Dalston.SR5)--Config 集群配置中心

Spring Cloud Config 是一个全新的项目,用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,他分为服务端和客户端两个部分.服务端也称为分布式配置中心,是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息.加密.解密信息等访问接口:而客户端则是为微服务架构中的各个微服务应用,通过指定的配置中心来管理应用资源与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息.服务端与客户端的结构图如下: ? ? ? ? Spring Cloud 程序在进行

windows下hadoop的集群分布式部署

下面我们进行说明一下hadoop集群的搭建配置. 本文假设读者具有hadoop单机配置的基础,相同的部分不在重述. 以三台测试机为例搭建一个小集群,三台机器的ip分别为 192.168.200.1;192.168.200.2;192.168.200.3 cygwin,jdk的安装同windows下hadoop的单机伪分布式部署(1),这里略过. 1.配置 hosts 在三台机子的hosts文件中加入如下记录: 192.168.200.1 hadoop1  #master namenode 192

Memcached集群/分布式/高可用 及 Magent缓存代理搭建过程 详解

当网站访问量达到一定时,如何做Memcached集群,又如何高可用,是接下来要讨论的问题. 有这么一段文字来描述“Memcached集群” Memcached如何处理容错的? 不处理!:) 在memcached节点失效的情况下,集群没有必要做任何容错处理.如果发生了节点失效,应对的措施完全取决于用户.节点失效时,下面列出几种方案供您选择: * 忽略它! 在失效节点被恢复或替换之前,还有很多其他节点可以应对节点失效带来的影响. * 把失效的节点从节点列表中移除.做这个操作千万要小心!在默认情况下(

集群分布式 Hadoop安装详细步骤

集群分布式Hadoop系统安装及测试 本系统一共有三个节点,一个namenode,两个datanode,IP和主机名对应如下: 192.168.1.19           namenode 192.168.1.7             datanode1 192.168.1.20           datanode2 1.安装配置 1).安装配置JDK,在三个节点都需要安装,下面操作在三个节点上都需要执行: a.下载jdk-6u45-linux-x64.bin文件,将下载的文件放到/usr

Hadoop学习笔记_8_实施Hadoop集群 --分布式安装Hadoop

实施Hadoop集群 --分布式安装Hadoop 说明: 以Ubuntu配置为例,其中与CentOS不同之处会给出详细说明 现有三台服务器:其IP与主机名对应关系为: 192.168.139.129 master #NameNode/JobTrackerr结点 192.168.139.132 slave01 #DataNode/TaskTracker结点 192.168.139.137 slave02 #DataNode/TaskTracker结点 一.配置ssh实现Hadoop节点间用户的无密

集群分布式基础概念及了解

集群:集中力量办一件事,一个业务功能节点对应多个服务器,一个服务器挂了,这个功能还能做. 分布式:不同的事交给不同的来做,每个服务器对应一个任务,这个服务器挂了,这个功能就完蛋. 例如:如果一个大碉堡里面有五个小碉堡.分布式的话就是每个小碉堡下面安一个手榴弹,每个手榴弹负责爆破一个碉堡,集群的话就是搞一个集束手榴弹,把大碉堡直接爆破.效果是差不多的 微服务:相较于分布式,微服务的功能划分更细,分布式的每个服务器上的服务功能可能比较杂,但是微服务每台服务器上部署的服务功能更为细小,更具体,服务的耦

集群,分布式,微服务概念和区别理解

集群,分布式,微服务概念和区别理解 2018年02月04日 01:19:12 竹上 阅读数:18684 概念: 集群是个物理形态,分布式是个工作方式. 分布式:一个业务分拆多个子业务,部署在不同的服务器上 集群:同一个业务,部署在多个服务器上 1:分布式是指将不同的业务分布在不同的地方.而集群指的是将几台服务器集中在一起,实现同一业务. 分布式中的每一个节点,都可以做集群.而集群并不一定就是分布式的. 举例:就比如新浪网,访问的人多了,他可以做一个群集,前面放一个响应服务器,后面几台服务器完成同

Spring整合Quartz框架实现定时任务跑批(Maven完整版)

Quartz 介绍Quartz is a full-featured, open source job scheduling service that can be integrated with, or used along side virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to