spring事务传播机制

2019-01-10  本文已影响0人  smallAttr

问题描述

最近在项目优化过程中,遇到一个问题:因为前段时间把一个功能单拎出来弄成一个项目,这次优化就是实现代码的解耦,所以相关逻辑代码删除并通过HTTP的方式调用。完成代码优化后,通过jmeter run testCases。发现根据主键ID查询数据返回NULL。


流程图

分析过程

  1. 当发现这个问题,我第一反应会不会是RPC调用出现问题了,查看日志发现不是想象这样,而是实实在在的查询结果为NULL。
  2. 查看代码逻辑,插入逻辑和查询逻辑放在一个大方法里面,大概定位是因为事务没有提交,数据还未持久化到数据库中,进而查看配置文件,关于事务配置。如下:
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
</bean>
<aop:config>
        <aop:pointcut id="pointcut"  expression="execution(* com.github.smallAttr.*.service.*.*(..)) || execution(* com.github.smallAttr.*.business.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut"/>
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- the transactional semantics... -->
        <tx:attributes>
            <!-- all methods starting with 'get' are read-only -->
            <!--<tx:method name="get*" read-only="true"/>-->
            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="*"/>
        </tx:attributes>
</tx:advice>

果然直接在类上面声明事务(说明:相当于在该类所有public方法上加上@Transcational注解),进而证实了刚才的猜想。

我感觉这样的配置真的不是最佳实践。不需要的地方也加上了。正常情况下,事务传播机制保证只有外层事务生效,但是总给人的感觉是代码不可控。尤其是遇到特殊情况下,这很难修改,要满足情况,代码写得很丑陋,还得写上一大堆注释,以防后续partner给修改了。

解决方案

插入逻辑新启一个事务Propagation.REQUIRES_NEW,保证数据持久化再查询。

这实际修改过程中,也是走了不少弯路

  1. 同一个类中,事务声明 REQUIRES -> REQUIRES_NEW,事务未生效。
  2. REQUIRES -> REQUIRES_NEW处于不同类中(REQUIRES_NEW所在的方法未实现接口),事务未生效。
  3. REQUIRES -> REQUIRES_NEW处于不同类中(REQUIRES_NEW所在的方法实现接口),事务生效。

说实话,虽然问题得一解决,但是在这过程中还是存在很多疑点,时间空闲点我会好好梳理下并证实。

查找问题过程中,发现这两篇文章不错:

上一篇下一篇

猜你喜欢

热点阅读