最近工做发现,有个项目偶尔会报Couldn't rollback jdbc connection. No operations allowed after connection closed
,项目技术选型以下:html
从异常来看,是jdbc链接关闭后,代码中依然拿出来使用了,从而报错。进一步了解到,mysql链接默认的最长维持时间是8小时,即创建链接后,若是8小时内客户端没关闭链接,mysql就会把链接关闭,若是客户端拿到了这个链接,就会报错了。这种状况通常会发生在链接池的状况下,由于在链接池中,为了提升资源利用率,链接使用完以后通常不会关闭,而是返回链接池中,等待下次使用。mysql
网上提供的解决方法以下:spring
以上两种方法一个是从服务端出发,一个是从客户端出来。因为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>