近期項目中,用 jenkins 熱部署 web工程時,發現工程中靜態持有的線程(將ScheduledExecutorService定時任務存儲在靜態Map中),導致不定時出現資料庫訪問事務關閉異常,如下:org.springframework.transaction.CannotCreateTran ...
近期項目中,用 jenkins 熱部署 web工程時,發現工程中靜態持有的線程(將ScheduledExecutorService定時任務存儲在靜態Map中),導致不定時出現資料庫訪問事務關閉異常,如下:org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: EntityManagerFactory is closed
看到該問題,一直認為是操作資料庫的類沒有事務聲明,所以在類上加上@Transactional,但沒生效。並且程式不定期的調用工程中的Runnable類,然後報以上錯誤。明明只有一個線程,卻出現多個線程運行,猜想應該是之前熱部署時,存儲在靜態資源中的定時線程沒有清除。重啟Tomcat,發現不會報錯了。故定位為Tomcat熱部署,靜態資源為釋放。
猜想:遺留線程未釋放,仍在運行,此時操作資料庫,出現創建事務失敗的異常,應該是web工程熱部署後,Spring的事務管理已失效,無法創建事務。
解決方法:
(1)使用Java EE5中的註解@PreDestroy
(2)使用Spring中的DisposableBean或配置destroy-method。(類實現 DisposableBean 介面,在 destroy() 方法中實現資源釋放)
參考:
透徹的掌握 Spring 中@transactional 的使用
jenkins tomcat熱部署,任務線程重覆啟動的解決方法
註解@PostConstruct與@PreDestroy詳解及實例
Spring@PostConstruct和@PreDestroy實例
Spring Bean InitializingBean和DisposableBean實例