最近工做發現,有個項目偶爾會報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>