@Transactional失效场景汇总
- 数据库引擎不支持事务
- 异常被catch捕获导致@Transactional失效
- 如果Transactional注解应用在非public 修饰的方法上,Transactional将会失效。
- @Transactional 注解属性 propagation 设置错误,以下三种 propagation,事务将不会发生回滚。
- TransactionDefinition.PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
- TransactionDefinition.PROPAGATION_NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
- @Transactional 注解属性 rollbackFor 设置错误 Spring默认在抛出了未检查unchecked异常(继承自 RuntimeException 的异常)或者 Error时才回滚事务;其他异常不会触发回滚事务。如果在事务中抛出其他类型的异常,但却期望 Spring 能够回滚事务,就需要指定 rollbackFor属性。
- 同一个类中方法调用,导致@Transactional失效
@Service
public class DeptServiceImpl implements DeptService {
@Resource
private DeptMapper deptMapper;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public int deleteByDeptno(Integer deptno) {
deptMapper.deleteByPrimaryKey(deptno);
throw new RuntimeException();//模拟出错
}
@Override
public int save(Dept record) {
int res1 = deptMapper.insert(record);//插入
int res2 = deleteByDeptno(83); //没有使用代理,事务传播不会生效
return res1 + res2; //模拟出错
}
}
测试代码
@SpringBootTest
class DeptServiceImplTest {
@Resource
private DeptService deptService;
@Test
void insert() {
Dept dept = Dept.builder()
.dname("bb")
.loc("bbbbbbbbb").build();
int insert = deptService.insert(dept);
System.out.println(insert);
}
}
尽管deleteByDeptno()方法开启了事务,但save()方法中调用deleteByDeptno()方法进没有使用代理,所以事务传播不会生效,即出错事务不会回滚。
Service层代码@Service
public class DeptServiceImpl implements DeptService {
@Resource
private DeptMapper deptMapper;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public int deleteByPrimaryKey(Integer deptno) {
deptMapper.deleteByPrimaryKey(deptno);
throw new RuntimeException();//模拟出错
}
@Resource
private DeptService deptService;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public int insert(Dept record) {
int res1 = deptMapper.insert(record);//插入
int res2 = deptService.deleteByPrimaryKey(83);//使用了代理,事务会回滚
//System.out.println(3 / 0);
return res1 + res2; //模拟出错
}
}
deleteByDeptno()方法开启了事务,save()方法中调用deleteByDeptno()方法进使用了代理,所以事务传播会生效,即出错事务会回滚。