背景
写了一个函数,分别支持手动调用和定时任务调用。
测试的时候一直用手动点击按钮触发函数,功能可用
等到了测试定时任务的时候,后台报错
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>
定时任务调度成功!
血泪教训,写代码一定要规范。其实这块最好的修改,应该是修改包结构,改为统一的包结构,这样就没有问题了。