背景
寫了一個函數,分別支持手動調用和定時任務調用。
測試的時候一直用手動點擊按鈕觸發函數,功能可用
等到了測試定時任務的時候,后臺報錯
Could not obtain transaction-synchronized Session for current thread
錯誤分析
- 事務管理不匹配:你的代碼是在 Spring 調度任務中執行的,但沒有正確配置事務支持
- 線程上下文問題:定時任務可能在獨立線程中執行,沒有事務上下文
- 服務層缺少事務注解:調用的服務方法沒有被事務管理器管理
解決思路
在報錯的實現層代碼上,增加事務注解
// 添加事務注解@Transactional@Overridepublic void saveSplitAndFile(...) {// 這里調用查詢方法// 其他業務邏輯}
一般到這步就可以了。但是我的代碼還是繼續報錯,于是我給每個報錯的代碼,都加上了事務注解,并且給定時任務的實現函數也增加了事務注解。
運行,繼續報錯。
于是決定查看AOP配置,看當前的實現類是否在事務中正確配置了,一檢查,果然發現問題。我們代碼中的配置
<aop:config><aop:pointcut id="transactionPointcut" expression="execution(* com.pms.*.service.impl.*.*(..))" /><aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" /></aop:config>
我找到報錯的調用函數,發現它的包結構,是在pms的業務包下,又新建了一個業務包,這樣,AOP切片就找不到這個函數
正常包結構
com
--pms
----biz
------service
--------impl
新業務的包結構
com
--pms
----biz
------service
--------impl
------bizChild
--------service
----------impl
于是修改AOP切片代碼
<aop:config><aop:pointcut id="transactionPointcut" expression="execution(* com.pms.*.service.impl.*.*(..))||execution(* com.pms.bizChild.*.service.impl.*.*(..))" /><aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" /></aop:config>
定時任務調度成功!
血淚教訓,寫代碼一定要規范。其實這塊最好的修改,應該是修改包結構,改為統一的包結構,這樣就沒有問題了。