问题描述
最近在项目优化过程中,遇到一个问题:因为前段时间把一个功能单拎出来弄成一个项目,这次优化就是实现代码的解耦,所以相关逻辑代码删除并通过HTTP的方式调用。完成代码优化后,通过jmeter run testCases。发现根据主键ID查询数据返回NULL。
流程图
分析过程
- 当发现这个问题,我第一反应会不会是RPC调用出现问题了,查看日志发现不是想象这样,而是实实在在的查询结果为NULL。
- 查看代码逻辑,插入逻辑和查询逻辑放在一个大方法里面,大概定位是因为事务没有提交,数据还未持久化到数据库中,进而查看配置文件,关于事务配置。如下:
<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
,保证数据持久化再查询。
这实际修改过程中,也是走了不少弯路
- 同一个类中,事务声明 REQUIRES -> REQUIRES_NEW,事务未生效。
- REQUIRES -> REQUIRES_NEW处于不同类中(REQUIRES_NEW所在的方法未实现接口),事务未生效。
- REQUIRES -> REQUIRES_NEW处于不同类中(REQUIRES_NEW所在的方法实现接口),事务生效。
说实话,虽然问题得一解决,但是在这过程中还是存在很多疑点,时间空闲点我会好好梳理下并证实。
查找问题过程中,发现这两篇文章不错:
网友评论