最近遇到一个问题对spring的注解事务有一个全新的认识,网上的资料有得说xml比注解高,有得说xml比注解低低,而我最开始的认为注解比xml要高,首先在系统在xml里面配置了事务方式,但是最近遇到一个业务的时候出现了一个问题,例如测试代码如下

public void updateCustomerByTest() throws BusinessException {
 
this.getIbatisBaseDAO().update(SQL_NAMESPACE_PREFIX+"updateCnfAccUser");
userHelper.queryTestDetail("100001", "1000010000001");
}

其中xml的配置如下

<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="update*" propagation="REQUIRED" rollback-for="Throwable" />
<tx:method name="query*" propagation="NOT_SUPPORTED" />
</tx:attributes>
</tx:advice>

其中updateCustomerByTest方法就是开启一个事务

this.getIbatisBaseDAO().update(SQL_NAMESPACE_PREFIX+"updateCnfAccUser");更新一个条记录

userHelper.queryTestDetail("100001", "1000010000001");去查询这条更新的记录,但是由于查询是NOT_SUPPORTED,所以会把当前事务挂起,已非事务的方式运行,这样查询就会出现锁等情况

这种情况下我在

@Transactional(propagation = Propagation.SUPPORTS)

在userHelper.queryTestDetail方法上,以为注解的优先级会高于xml,但是方法还是会出现锁等的情况,那似乎xml的优先级比注解要高,因为注解没有生效

 

最后我发现了在优先级上出现了一个理解的问题,首先spring的事务管理都是基于代理去实现,那么如果存在注解事务的话,那么也会出现一个代理切面,那么根据spring的切面顺寻order属性,注解默认配置的order为200,这样相当与注解的代理切面是最后一个执行,因此注解在某些情况下会覆盖xml

 

本次问题的出现主要原因是xml里面配置了propagation="NOT_SUPPORTED" ,这样相当于在该切面以后的代码都是非事务环境,而且还会把之前的事务挂起(updateCustomerByTest事务挂起),即使注解里面是@Transactional(propagation = Propagation.SUPPORTS),因为最后一个切面已经是非事务环境,查询的时候的锁被挂起事务获得,因此出现锁等

 

同理我把xml里面的配置改成<tx:method name="query*" propagation="SUPPORTS" />,而注解改成@Transactional(propagation = Propagation.NOT_SUPPORTED),这样同样也出现了锁等,这给人的感觉是注解覆盖了xml,

同理有测试了一下各种场景比如xml文件是<tx:method name="query*" propagation="NOT_SUPPORTED" />

注解是@Transactional(propagation = Propagation.REQUIRED)或者@Transactional(propagation = Propagation.REQUIRE_NEW)都出现了锁等。

 

其实解决问题的思路很简单,只要把<tx:method name="query*" propagation="SUPPORTS" />,去掉注解的配置就可以了,之前说的优先级只是说注解切面的order是最后一个,但是不能说他一定能覆盖xml,因为这个不是覆盖的关系,而是切面顺序执行的关系,有些时候出现的疑惑也往往是理解偏差引起,回顾一下项目里面用到的注解是REQUIRE_NEW覆盖xml的REQUIRED其实也是理解错误。