quartz异常:Couldn't rollback jdbc connection

最近工做发现,有个项目偶尔会报Couldn't rollback jdbc connection. No operations allowed after connection closed,项目技术选型以下:html

  • 数据库mysql
  • 链接池druid
  • quartz

从异常来看,是jdbc链接关闭后,代码中依然拿出来使用了,从而报错。进一步了解到,mysql链接默认的最长维持时间是8小时,即创建链接后,若是8小时内客户端没关闭链接,mysql就会把链接关闭,若是客户端拿到了这个链接,就会报错了。这种状况通常会发生在链接池的状况下,由于在链接池中,为了提升资源利用率,链接使用完以后通常不会关闭,而是返回链接池中,等待下次使用。mysql

网上提供的解决方法以下:spring

  1. 延长mysql的链接维持时间,须要修改mysql配置;
  2. 从链接池中获取链接时,校验链接的有效性。

以上两种方法一个是从服务端出发,一个是从客户端出来。因为mysql权限问题,没法直接修改mysql的配置,所以只能从客户端入手了。sql

项目中使用的链接池是druid,理所固然是druid的问题,baidu了下一圈下来,druid相关的设置以下:数据库

<!-- 获取链接时检查链接是否可用,官方说会影响性能,不建议开启-->
<property name="testOnBorrow" value="false" />
<!-- 归还链接时检查链接是否可用,官方说会影响性能,不建议开启-->
<property name="testOnReturn" value="false" />
<!-- 空闲时检查,再配合多久检查一次,官方建议使用的方式 -->
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 检查语句 -->
<property name="validationQuery" value="SELECT 'x'" />

对照项目中的配置发现,二者基本一致。看来问题并不在druid。性能

再分析异常信息,发现报错都是在quartz相关的类中,所以将焦点转向了quartz。ui

在quartz中,发现有一段配置是这样的:url

<bean id="schedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
  <property name="quartzProperties">
  	<props>
  	  <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
  	  <prop key="org.quartz.threadPool.threadCount">50</prop>
  	  <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
  	  <prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop>
  	  <prop key="org.quartz.jobStore.dataSource">member</prop>
  	  <prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
	  	<!-- quartz数据库配置 -->
  	  <prop key="org.quartz.dataSource.member.driver">com.mysql.jdbc.Driver</prop>
  	  <prop key="org.quartz.dataSource.member.URL">${member.jdbc.url}</prop>
  	  <prop key="org.quartz.dataSource.member.user">${member.jdbc.username}</prop>
  	  <prop key="org.quartz.dataSource.member.password">${member.jdbc.password}</prop>
  	  <prop key="org.quartz.dataSource.member.maxConnections">10</prop>
  	</props>
  </property>
</bean>

这里能够发现,quartz并无使用druid链接池,而是从新开启数据库链接。在quartz 2.2.1 jdbc 链接池参数配置中,知道了quartz默认的链接是c3p0,而且了解了相关配置项。继续搜索,发现有人也踩过这个坑:quartz和数据库断链接的解决办法,结合这两篇文章,我给出的解决方案以下:.net

<bean id="schedulerFactoryBean"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
  <property name="quartzProperties">
  	<props>
  	  <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
  	  <prop key="org.quartz.threadPool.threadCount">50</prop>
  	  <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
  	  <prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop>
  	  <prop key="org.quartz.jobStore.dataSource">member</prop>
  	  <prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
  	  <prop key="org.quartz.dataSource.member.driver">com.mysql.jdbc.Driver</prop>
  	  <prop key="org.quartz.dataSource.member.URL">${member.jdbc.url}</prop>
  	  <prop key="org.quartz.dataSource.member.user">${member.jdbc.username}</prop>
  	  <prop key="org.quartz.dataSource.member.password">${member.jdbc.password}</prop>
  	  <prop key="org.quartz.dataSource.member.maxConnections">10</prop>
  	  <!-- 添加的配置 -->
  	  <prop key="org.quartz.dataSource.member.validateOnCheckout">true</prop>
  	  <prop key="org.quartz.dataSource.member.validationQuery">SELECT 'x'</prop>
  	</props>
  </property>
</bean>

只是在quartz配置文件中添加了两行:code

<!-- 从链接池中获取链接时,验证链接是否有效 -->
<prop key="org.quartz.dataSource.member.validateOnCheckout">true</prop>
<!-- 验证语句 -->
<prop key="org.quartz.dataSource.member.validationQuery">SELECT 'x'</prop>
相关文章
相关标签/搜索