小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
最近项目中写业务的时候遇到了小问题,在操作多个表时,多个业务处理方法使用了@Transactional开启事务,但是在测试的时候发现执行失败时事务并没有回滚,这让对@Transactional事务一知半解的我大受震撼,便准备一探究竟,顺便学上一手。
1. 问题再现
1.1 业务代码信息
业务实体类信息:
@Data
public class ProductCodeEntity {
/**
* Id
*/
private Long productCodeId;
/**
* 子类集合
*/
private List<CodeMatnrRelatedEntity> productMatrialList;
...
}
对上层暴露的业务方法:
//控制层调用的业务方法
public void save(ProductCodeEntity entity) {
//一些其他逻辑的处理
...
saveProductCodeInfo(entity);
}
主表业务处理逻辑:
//主表保存
@Transactional(rollbackFor = Exception.class)
public void saveProductCodeInfo(ProductCodeEntity entity) {
productCodeMapper.save(entity);
if(CollectionUtils.isNotEmpty(entity.getProductMatrialList())){
entity.getProductMatrialList().stream().forEach(a -> a.setProductCodeId(entity.getProductCodeId()));
codeMatnrRelatedService.batchSave(entity.getProductMatrialList());
}
}
子表业务处理逻辑:
//子表批量保存
@Transactional(rollbackFor = Exception.class)
public int batchSave(List<CodeMatnrRelatedEntity> entityList) {
return codeMatnrRelatedMapper.batchSave(entityList);
}
1.2 业务功能描述
- 在进行业层逻辑处理时,由于涉及到一些其他数据的计算,抽取了单独的方法,并在对外暴露的业务方法中调用,之后再调用保存方法并传入参数。
- 主表数据保存方法中调用子表信息的批量保存,在数据正常时两表数据均保存成功;但是当主表保存成功后子表数据出现了异常,此时@Transactional注解并没有将事务进行回滚。
2. @Transaction注解
2.1 @Transaction是什么
- @Transaction注解是Spring框架提供的一种声明式事务,建立在Spring的AOP至上。声明式事务的本质是在方法的前后进行拦截,在目标方法开始时进行事务创建或者加入一个已经创建的事务,而在方法执行完成后对事务进行提交或者回滚。
- 在SpringBoot中使用@Transaction注解标注在方法之上,便对当前方法开启了事务。
- @Transaction注解可以应用在接口、接口方法、类以及类方法上。
2.2 @Transaction的使用
- 在项目的启动类上添加@EnableTransactionManagement注解
- 注解加在类上则类中所有方法都会应用到,如果加在方法仅当前方法应用到
- @Transaction注解可以配置回滚异常的范围,默认是RuntimeException事务回滚,可以使用@Transaction(rollbackFor=Exception.class)来设置所有异常时事务回滚
- 使用@Transaction注解后,当遇到符合范围的异常时,事务回滚,数据库数据也会回滚。
2.3 @Transaction的失效情境
了解了@Transaction注解的使用方式,便可以在项目中使用事务来保证业务处理的原子性了。但是,实际使用过程中往往会遇到很多情境,导致事务并没有生效,在此总结一下失效的情况。
- @Transaction注解加在了非public的方法上,此时Spring不会进行事务配置
- 同一个类中的方法调用了另一个方法,而调用方法没有使用注解,导致被调用方法即使使用注解也是无效的
- 项目中就是碰到了这种情况才导致了事务没有生效
- 使用@Transaction注解的方法中,产生的异常使用catch进行了处理,导致异常没有被抛出,此时事务不会回滚
- @Transaction注解的异常范围设置不对,出现了范围之外的异常,此时事务不会回滚
- 默认是遇到RuntimeException异常回滚
3. 总结
@Transaction注解实现事务,一个小小的注解,使用起来也非常方便,但是存在的问题还是不少的,要想用好事务还是要认真的了解@Transaction注解实现的机制呀。