使用quartz对做业进行调度时,报出下列异常:html
2018-09-27 06:00:00,149 WARN [org.quartz.impl.jdbcjobstore.JobStoreTX] Failed to override connection auto commit/transaction isolation. com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 437823 seconds ago.The last packet sent successfully to the server was 437823 seconds ago, which is longer than the server configured value of 'wait_timeout'. You should consider either expiring and/or testing connection validity before use in your application, increasing the server configured values for client timeouts, or using the Connector/J connection property 'autoReconnect=true' to avoid this problem. at sun.reflect.GeneratedConstructorAccessor246.newInstance(Unknown Source) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl. java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.mysql.jdbc.Util.handleNewInstance(Util.java:406) [Scheduler_QuartzSchedulerThread] WARN org.quartz.impl.jdbcjobstore.JobStoreTX - Failed to override connection auto commit/transaction isolation. com.mysql.jdbc.CommunicationsException: Communications link failure due to underlying exception: ** BEGIN NESTED EXCEPTION ** java.net.SocketException MESSAGE: Broken pipe STACKTRACE: java.net.SocketException: Broken pipe at java.net.SocketOutputStream.socketWrite0(Native Method) at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92) at java.net.SocketOutputStream.write(SocketOutputStream.java:136) at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:65) at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:123) at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:2744) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1612) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:1723) at com.mysql.jdbc.Connection.execSQL(Connection.java:3277) at com.mysql.jdbc.Connection.setAutoCommit(Connection.java:5442) at org.apache.commons.dbcp.DelegatingConnection.setAutoCommit(DelegatingConnection.java:237) at org.quartz.impl.jdbcjobstore.AttributeRestoringConnectionInvocationHandler.setAutoCommit(AttributeRestoringConnectionInvocationHandler.java:91) at org.quartz.impl.jdbcjobstore.AttributeRestoringConnectionInvocationHandler.invoke(AttributeRestoringConnectionInvocationHandler.java:65) at $Proxy4.setAutoCommit(Unknown Source) at org.quartz.impl.jdbcjobstore.JobStoreSupport.getConnection(JobStoreSupport.java:711) at org.quartz.impl.jdbcjobstore.JobStoreTX.getNonManagedTXConnection(JobStoreTX.java:72) at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3757) at org.quartz.impl.jdbcjobstore.JobStoreSupport.acquireNextTrigger(JobStoreSupport.java:2729) at org.quartz.core.QuartzSchedulerThread.run(QuartzSchedulerThread.java:266) ** END NESTED EXCEPTION **
使用的quartz版本为2.2.3,数据库的配置以下:java
org.quartz.jobStore.dataSource = myDS org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz?autoReconnect=true&characterEncoding=utf-8 org.quartz.dataSource.myDS.user = root org.quartz.dataSource.myDS.password = root org.quartz.dataSource.myDS.maxConnections =50
MySql服务器默认的“wait_timeout”是8小时,也就是说一个connection空闲超过8个小时,MySql将自动断开该connection。 这就是问题的所在,在C3P0 pools中的connections若是空闲超过8小时,MySql将其断开,而C3P0并不知道该connection已经失效,若是这时有Client请求connection,C3P0将该失效的Connection提供给Client,将会形成上面的异常。mysql
quartz定时任务使用时数据库链接默认是maxIdleTime=0,即永不放弃链接。在Spring Boot启动服务,控制台打印的quartz数据库配置信息以下:web
2018-09-28 14:38:31.957 INFO 13932 --- [ main] com.mchange.v2.c3p0.C3P0Registry : Initializing c3p0-0.9.1.1 [built 15-March-2007 01:32:31; debug? true; trace: 10] 2018-09-28 14:38:31.988 INFO 13932 --- [ main] org.quartz.impl.StdSchedulerFactory : Using default implementation for ThreadExecutor 2018-09-28 14:38:32.018 INFO 13932 --- [ main] org.quartz.core.SchedulerSignalerImpl : Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl 2018-09-28 14:38:32.018 INFO 13932 --- [ main] org.quartz.core.QuartzScheduler : Quartz Scheduler v.2.2.3 created. 2018-09-28 14:38:32.019 INFO 13932 --- [ main] org.quartz.impl.jdbcjobstore.JobStoreTX : Using db table-based data access locking (synchronization). 2018-09-28 14:38:32.021 INFO 13932 --- [ main] org.quartz.impl.jdbcjobstore.JobStoreTX : JobStoreTX initialized. 2018-09-28 14:38:32.021 INFO 13932 --- [ main] org.quartz.core.QuartzScheduler : Scheduler meta-data: Quartz Scheduler (v2.2.3) 'MyScheduler' with instanceId 'MyScheduler' Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 50 threads. Using job-store 'org.quartz.impl.jdbcjobstore.JobStoreTX' - which supports persistence. and is clustered. 2018-09-28 14:38:32.021 INFO 13932 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler 'CMDBScheduler' initialized from an externally provided properties instance. 2018-09-28 14:38:32.021 INFO 13932 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler version: 2.2.3 2018-09-28 14:38:32.021 INFO 13932 --- [ main] org.quartz.core.QuartzScheduler : JobFactory set to: com.cmb.cmdb.bean.JobFactory@26844abb 2018-09-28 14:38:32.083 INFO 13932 --- [ main] c.m.v.c.i.AbstractPoolBackedDataSource : Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, dataSourceName -> rhcsim9y8knjf2ph7q1r|51a6cc2a, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, identityToken -> rhcsim9y8knjf2ph7q1r|51a6cc2a, idleConnectionTestPeriod -> 50, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/quartz?autoReconnect=true&characterEncoding=utf-8, lastAcquisitionFailureDefaultUser -> null, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 50, maxStatements -> 0, maxStatementsPerConnection -> 120, minPoolSize -> 1, numHelperThreads -> 3, numThreadsAwaitingCheckoutDefaultUser -> 0, preferredTestQuery -> select 1, properties -> {user=******, password=******}, propertyCycle -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> true, unreturnedConnectionTimeout -> 0, usesTraditionalReflectiveProxies -> false ]
注意到**maxIdleTime -> 0**,这是由于默认**org.quartz.dataSource.myDS.discardIdleConnectionsSeconds**没有配置。该配置项表示数据库链接在空闲以后放弃链接几秒钟。0表示禁用该功能。默认值为0。
Quartz 2.0 之前 DBCPspring
Quartz 2.0 之后 C3P0(包含2.0)sql
DBCP(DataBase connection pool),数据库链接池。是 apache 上的一个 java 链接池项目,也是 tomcat 使用的链接池组件。单独使用DBCP须要3个包:common-dbcp.jar,common-pool.jar,common-collections.jar。因为创建数据库链接是一个很是耗时耗资源的行为,因此经过链接池预先同数据库创建一些链接,放在内存中,应用程序须要创建数据库链接时直接到链接池中申请一个就行,用完后再放回去。数据库
C3P0是一个开源的JDBC链接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。apache
DBCP没有自动的去回收空闲链接的功能, C3P0有自动回收空闲链接功能。 二者主要是对数据链接的处理方式不一样,C3P0提供最大空闲时间,DBCP提供最大链接数。 前者当链接超过最大空闲链接时间时,当前链接就会被断掉。DBCP当链接数超过最大链接数时,全部链接都会被断开。DBCP的原理是维护多个链接对象Connection,在web项目要链接数据库时直接使用它维护的对象进行链接,省去每次都要建立链接对象的麻烦。提升效率和减小内存使用。C3P0能够自动回收链接,DBCP须要本身手动释放资源返回。不过DBCP效率比较高。缓存
<!-- 配置dbcp数据源 --> <bean id="dataSource2" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> <!-- 池启动时建立的链接数量 --> <property name="initialSize" value="5"/> <!-- 同一时间能够从池分配的最多链接数量。设置为0时表示无限制。 --> <property name="maxActive" value="30"/> <!-- 池里不会被释放的最多空闲链接数量。设置为0时表示无限制。 --> <property name="maxIdle" value="20"/> <!-- 在不新建链接的条件下,池中保持空闲的最少链接数。 --> <property name="minIdle" value="3"/> <!-- 设置自动回收超时链接 --> <property name="removeAbandoned" value="true" /> <!-- 自动回收超时时间(以秒数为单位) --> <property name="removeAbandonedTimeout" value="200"/> <!-- 设置在自动回收超时链接的时候打印链接的超时错误 --> <property name="logAbandoned" value="true"/> <!-- 等待超时以毫秒为单位,在抛出异常以前,池等待链接被回收的最长时间(当没有可用链接时)。设置为-1表示无限等待。 --> <property name="maxWait" value="100"/> </bean> <!-- 配置c3p0数据源 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="driverClass" value="${jdbc.driverClassName}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> <!--链接池中保留的最大链接数。Default: 15 --> <property name="maxPoolSize" value="100" /> <!--链接池中保留的最小链接数。--> <property name="minPoolSize" value="1" /> <!--初始化时获取的链接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 --> <property name="initialPoolSize" value="10" /> <!--最大空闲时间,60秒内未使用则链接被丢弃。若为0则永不丢弃。Default: 0 --> <property name="maxIdleTime" value="30" /> <!--当链接池中的链接耗尽的时候c3p0一次同时获取的链接数。Default: 3 --> <property name="acquireIncrement" value="5" /> <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但因为预缓存的statements属于单个 connection而不是整个链接池。因此设置这个参数须要考虑到多方面的因素。若是maxStatements与 maxStatementsPerConnection均为0,则缓存被关闭。Default: 0--> <property name="maxStatements" value="0" /> <!--每60秒检查全部链接池中的空闲链接。Default: 0 --> <property name="idleConnectionTestPeriod" value="60" /> <!--定义在从数据库获取新链接失败后重复尝试的次数。Default: 30 --> <property name="acquireRetryAttempts" value="30" /> <!--获取链接失败将会引发全部等待链接池来获取链接的线程抛出异常。可是数据源仍有效保留,并在下次调用getConnection()的时候继续尝试获取链接。若是设为true,那么在尝试获取链接失败后该数据源将申明已断开并永久关闭。Default: false--> <property name="breakAfterAcquireFailure" value="true" /> <!--因性能消耗大请只在须要的时候使用它。若是设为true那么在每一个connection提交的时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable等方法来提高链接测试的性能。Default: false --> <property name="testConnectionOnCheckout" value="false" /> </bean>
若是您使用JDBC-Jobstore,则须要使用DataSource(或使用两个DataSource,若是您使用JobStoreCMT)。 DataSources能够经过三种方式进行配置:
自定义的org.quartz.utils.ConnectionProvider实现。tomcat
建议您将Datasource max链接大小配置为至少线程池中的工做线程数量加上三个。若是您的应用程序也频繁调用调度程序API,则可能须要其余链接。若是您使用JobStoreCMT,则“非受管理”数据源的最大链接大小应至少为4。
您定义的每一个DataSource(一般为一个或两个)必须为一个名称,而且您为每一个定义的属性必须包含该名称,以下所示。DataSource的“NAME”能够是任何您想要的,除了可以在分配给JDBCJobStore以后可以识别它以外,没有什么意义。
Property Name | Required | Type | Default Value |
---|---|---|---|
org.quartz.dataSource.NAME.driver | yes | String | null |
org.quartz.dataSource.NAME.URL | yes | String | null |
org.quartz.dataSource.NAME.user | no | String | "" |
org.quartz.dataSource.NAME.password | no | String | "" |
org.quartz.dataSource.NAME.maxConnections | no | int | 10 |
org.quartz.dataSource.NAME.validationQuery | no | String | null |
org.quartz.dataSource.NAME.idleConnectionValidationSeconds | no | int | 50 |
org.quartz.dataSource.NAME.validateOnCheckout | no | boolean | false |
org.quartz.dataSource.NAME.discardIdleConnectionsSeconds | no | int | 0 (disabled) |
org.quartz.dataSource.NAME.driver
必须是数据库的JDBC驱动程序的java类名称。
org.quartz.dataSource.NAME.URL
链接到数据库的链接URL(主机,端口等)。
org.quartz.dataSource.NAME.user
链接到数据库时要使用的用户名。
org.quartz.dataSource.NAME.password
链接到数据库时使用的密码。
org.quartz.dataSource.NAME.maxConnections
DataSource能够在其链接池中建立的最大链接数。
org.quartz.dataSource.NAME.validationQuery
是可选的SQL查询字符串,DataSource可用于检测和替换失败/损坏的链接。例如,oracle用户可能会选择“从user_tables中选择table_name” - 这是一个不该该失败的查询 - 除非链接其实是坏的。
org.quartz.dataSource.NAME.idleConnectionValidationSeconds
空闲链接测试之间的秒数 - 仅在设置验证查询属性时启用。默认值为50秒。
org.quartz.dataSource.NAME.validateOnCheckout
每次从池中检索链接时,是否应该执行数据库sql查询来验证链接,以确保它仍然有效。若是为假,则在办理登机手续时将进行验证。默认值为false。
org.quartz.dataSource.NAME.discardIdleConnectionsSeconds
它们在空闲以后放弃链接几秒钟。0禁用该功能。默认值为0。
Quartz定义的DataSource示例
org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@ 10.0.1.23:1521:demodb org.quartz.dataSource.myDS.user = myUser org.quartz.dataSource.myDS.password = myPassword org.quartz.dataSource.myDS.maxConnections = 30
对Application Server DataSources的引用使用如下属性定义:
Property Name | Required | Type | Default Value |
---|---|---|---|
org.quartz.dataSource.NAME.jndiURL | yes | String | null |
org.quartz.dataSource.NAME.java.naming.factory.initial | no | String | null |
org.quartz.dataSource.NAME.java.naming.provider.url | no | String | null |
org.quartz.dataSource.NAME.java.naming.security.principal | no | String | null |
org.quartz.dataSource.NAME.java.naming.security.credentials | no | String | null |
org.quartz.dataSource.NAME.jndiURL
由应用程序服务器管理的DataSource的JNDI URL。
org.quartz.dataSource.NAME.java.naming.factory.initial
要使用的JNDI InitialContextFactory的(可选)类名。
org.quartz.dataSource.NAME.java.naming.provider.url
用于链接到JNDI上下文的(可选)URL。
org.quartz.dataSource.NAME.java.naming.security.principal
用于链接到JNDI上下文的(可选)用户主体。
org.quartz.dataSource.NAME.java.naming.security.credentials
用于链接到JNDI上下文的(可选)用户凭据。
从应用程序服务器引用的数据源示例
org.quartz.dataSource.myOtherDS.jndiURL = JDBC / myDataSource org.quartz.dataSource.myOtherDS.java.naming.factory.initial = com.evermind.server.rmi.RMIInitialContextFactory org.quartz.dataSource.myOtherDS.java.naming.provider.url = ormi:// localhost org.quartz.dataSource.myOtherDS.java.naming.security.principal = admin org.quartz.dataSource.myOtherDS.java.naming.security.credentials = 123
自定义ConnectionProvider实现
Property Name | Required | Type | Default Value |
---|---|---|---|
org.quartz.dataSource.NAME.connectionProvider.class | yes | String (class name) | null |
org.quartz.dataSource.NAME.connectionProvider.class
要使用的ConnectionProvider的类名。实例化以后,Quartz能够自动设置实例上的配置属性,bean样式。
使用自定义ConnectionProvider实现的示例
org.quartz.dataSource.myCustomDS.connectionProvider.class = com.foo.FooConnectionProvider org.quartz.dataSource.myCustomDS.someStringProperty = someValue org.quartz.dataSource.myCustomDS.someIntProperty = 5
org.quartz.datasource.qzDS.validateOnCheckout=true org.quartz.datasource.qzDS.validationQuery=select 1 org.quartz.dataSource.myDS.discardIdleConnectionsSeconds=60