本文主要介绍使用spring管理事务时因为开发编码导致事务失效的场景,主要讲述开发最容易忽略的场景。
1.方法内部调用 + 事务传播行为配置不当场景
示例代码
@Slf4j
@Service
public class DemoServiceImpl implements DemoService {
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void service1() {
boolean active = TransactionSynchronizationManager.isActualTransactionActive();
log.info("service1 is exist transaction:{}", active);
if (active) {
String name = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("service1 transaction name:{}", name);
}
service2();
}
@Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
public void service2() {
boolean active = TransactionSynchronizationManager.isActualTransactionActive();
log.info("service2 is exist transaction:{}", active);
if (active) {
String name = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("service2 transaction name:{}", name);
}
}
}
测试代码
模拟Controller调用Service场景。
@SpringBootTest(classes = SpringBootTransactionApplication.class)
public class SpringBootTransactionTest {
@Autowired
private DemoService demoService;
@Test
void test() {
demoService.service1();
}
}
场景导入
上述示例代码中,service1方法内部调用了service2方法,由于service1方法和service2方法同属于一个service接口(类)中,并不能在service实现类中再注入自己本身,因此我们就随手写了一个service2(),亦或是this.service2(),于是问题就产生了!
问题分析
service1方法添加了 @Transactional 注解,并且指定了事务的传播行为是Propagation.REQUIRED(不做过多介绍),当测试代码调用service1方法时,spring会为DemoServiceImpl 生成一个代理对象,并且开启一个新事物(如果当前存在事务则加入)。当代码执行到service2方法时,由于默认使用this对象去调用,因此spring不会使用代理对象去调用service2方法,而是直接使用原生的对象去调用service2方法,相当于 new DemoServiceImpl().service2(),这样service2方法上添加的 @Transactional 注解就无效了,这就是方法内部调用导致的事物失效!
结果分析
虽然上述调用方式导致了service2方法上添加的 @Transactional 注解失效,但是不代表执行service2方法时就一定没有事务,业务上也不一定就错误。继续接着分析,当执行到serv

最低0.47元/天 解锁文章
979

被折叠的 条评论
为什么被折叠?



