XML多组合PointCut表达式解析及TransactionRequiredException排查
一、AOP配置里的&amp含义与整体逻辑
先给你拆解这个配置里的细节:
&amp的本质:你看到的&&其实是XML转义+HTML转义后的结果。在原生XML文件中,&是特殊字符,必须转义为&,所以逻辑与运算符&&在XML里要写成&&。而你看到的&是这段XML代码在网页展示时被再次HTML转义了,实际生效的是&&(逻辑与)。三个
<aop:advisor>的配置逻辑:- 第一个advisor:匹配
com.RR包下所有子包中manager层级下的所有public方法,但排除com.RR.DD.manager.IMan接口的isNonProductionEnvironment和isProductionEnvironment两个方法,给符合条件的方法绑定txAdvice事务通知。 - 第二个advisor:匹配
com.highradius包下所有子包中manager层级下的所有public方法,绑定事务通知。 - 第三个advisor:匹配
com.scraper.correspondence包下所有子包中manager层级下的所有public方法,绑定事务通知。
- 第一个advisor:匹配
二、TransactionRequiredException异常原因分析
从堆栈信息来看,异常出现在com.sun.proxy.$Proxy148.isTriggerEmailForNonProdEnvironment方法调用时,Hibernate尝试Flush Session但发现没有活跃事务。结合你的AOP配置,核心问题大概率是:
这个出问题的
isTriggerEmailForNonProdEnvironment方法不在事务切点的覆盖范围内
看堆栈里的调用链:com.scraper.EmailManagement类调用了这个方法,但你的第三个事务切点只覆盖com.scraper.correspondence..manager..*,而EmailManagement属于com.scraper根包下的类,不在切点范围内,所以这个方法执行时没有被Spring事务通知增强,也就没有开启事务。但方法内部可能触发了Hibernate的实体持久化/更新操作,导致Session需要Flush,而Flush必须在事务上下文里进行,最终抛出了no transaction is in progress异常。
另外还有一种小概率情况:如果这个方法是EmailManagement类内部的方法调用(比如同一个类里的方法互相调用),即使外部方法在事务范围内,Spring的动态代理也无法拦截内部调用,导致事务通知不生效。不过从堆栈里的代理类调用痕迹来看,这种可能性相对较低,但也需要排查。
三、解决思路
针对这个问题,你可以按以下步骤排查修复:
- 调整事务切点范围:检查
isTriggerEmailForNonProdEnvironment方法所在类的全限定名,如果属于com.scraper下的manager相关包,可修改第三个advisor的切点为execution(public * com.scraper..manager..*.*(..)),或者单独给该方法所在的包添加新的<aop:advisor>配置。 - 确认方法调用是否经过代理:如果是同一个类内部调用该方法,需要改成通过Spring代理对象调用:要么把该方法抽成独立的Spring Bean,通过依赖注入调用;要么在
<aop:config>里开启expose-proxy="true",然后用AopContext.currentProxy()获取自身代理对象来调用方法。 - 检查事务通知
txAdvice的配置:确认txAdvice里的事务传播行为是否为propagation="REQUIRED"(默认值),如果设置成SUPPORTS或NOT_SUPPORTED,会导致在无事务环境下不主动创建事务,需要调整为合适的传播行为。 - 验证Hibernate Session管理:确认Spring是否正确绑定了Session与事务,比如是否配置了
OpenSessionInViewFilter(如果是Web场景),或者事务注解/配置是否正确关联了SessionFactory。
内容的提问来源于stack exchange,提问作者DockYard

