文章目录
- 总结
- 1、同一个类中,方法内部调用事务失效(代理不生效导致)
- 2、事务方法被final、static修饰
- 3、当前类没有被Spring管理
- 4、非public修饰的方法(存在版本差异)
- 5、事务多线程调用
- 6、数据库本身不支持事务
- 7.异常被方法内部try catch捕获,没有重新抛出
- 8、嵌套事务回滚多了
- 9、rollbackFor属性设置错误
- 10、设置了不支持事务的传播机制
总结
1、同一个类中,方法内部调用事务失效
2、事务方法被final、static修饰
3、当前类没有被Spring管理
4、非public修饰的方法(存在版本差异)
5、事务多线程调用
6、数据库本身不支持事务
7、异常被方法内部try catch捕获,没有重新抛出
8、嵌套事务回滚多了
9、rollbackFor属性设置错误
10、设置不支持事务的传播机制
1、同一个类中,方法内部调用事务失效(代理不生效导致)
示例:同一个类中,addOrder()方法无事务,addOrder2()方法存在事务,addOrder()调用addOrder2()是失效的(非事务方法调用事务方法是无效的)
@Service public class OrderServiceImpl { @Autowired private OrderMapper orderMapper; public int addOrder(Double amount, String address) { int order = addOrder2(amount, address); return order; } @Transactional public int addOrder2(Double amount, String address) { int order = orderMapper.addOrder(amount, address); int i = order / 0; return order; } }
解决方案:
@Service public class OrderServiceImpl { @Autowired private OrderMapper orderMapper; @Transactional public int addOrder(Double amount, String address) { int order = addOrder2(amount, address); return order; } @Transactional public int addOrder2(Double amount, String address) { int order = orderMapper.addOrder(amount, address); int i = order / 0; return order; } }
2、事务方法被final、static修饰
事务失效的示例:
@Service public class OrderServiceImpl { @Autowired private OrderMapper orderMapper; @Transactional public final int addOrder(Double amount, String address) { int order = orderMapper.addOrder(amount, address); int i = order / 0; return order; } @Transactional public int addOrder2(Double amount, String address) { int order = orderMapper.addOrder(amount, address); int i = order / 0; return order; } }
3、当前类没有被Spring管理
例如:Service类中没有@Service注解
public class OrderServiceImpl { @Autowired private OrderMapper orderMapper; @Transactional public int addOrder(Double amount, String address) { int order = orderMapper.addOrder(amount, address); int i = order / 0; return order; } }
@Transactional事务生效的前提条件是需要代理类对目标方法的调用,才能触发事务处理,而代理类是在springBoot启动时创建bean的时候处理的。如果我们的类没有@Service注解,就不会交给spring容器初始化处理,也就无法为目标类生成代理类。
4、非public修饰的方法(存在版本差异)
在spring版本6.0.11中@Transactional是支持proected修饰的方法的
@Service public class OrderServiceImpl { @Autowired private OrderMapper orderMapper; @Transactional protected int addOrder(Double amount, String address) { int order = orderMapper.addOrder(amount, address); int i = order / 0; return order; } }
5、事务多线程调用
示例代码:
@Service public class OrderServiceImpl { @Autowired private OrderMapper orderMapper; @Autowired private SysUserServiceImpl sysUserService; @Transactional(rollbackFor = Exception.class) public int addOrder(Double amount, String address){ int order = orderMapper.addOrder(amount, address); new Thread(() -> { sysUserService.saveUser(); }).start(); return order; } }
6、数据库本身不支持事务
Spring事务的底层,还是依赖于数据库本身的事务支持。在MySQL中,Myisam存储引擎是不支持事务的,InnoDB引擎才支持事务。
这种问题出现的概率很小,在Mysql5之后,默认情况下是使用的InnoDB引擎存储
如果是历史项目,发现事务怎么配置都不生效,确认下你的存储引擎是否支持事务。
7.异常被方法内部try catch捕获,没有重新抛出
示例代码:
@Service public class OrderServiceImpl { @Autowired private OrderMapper orderMapper; @Transactional public int addOrder(Double amount, String address) { int order = 0; try { order = orderMapper.addOrder(amount, address); int i = order / 0; } catch (Exception e) { } return order; } }
8、嵌套事务回滚多了
示例代码:
@Service public class OrderServiceImpl { @Autowired private OrderMapper orderMapper; @Autowired private SysUserServiceImpl sysUserService; @Transactional(rollbackFor = Exception.class) public int addOrder(Double amount, String address){ int order = orderMapper.addOrder(amount, address); sysUserService.saveUser(); return order; } } @Service public class SysUserServiceImpl { @Transactional public void saveUser(){ throw new RuntimeException("新增人员失败"); } }
当出现嵌套事务发生异常的时候,实际上两个方法的事务都会进行回滚。
但是有一种场景,即使sysUserService.saveUser()方法发生异常,我们期望orderMapper.addOrder()方法执行的结果也正常入库。
解决办法:
1、addOrder()方法使用trye/catch包住
2、saveUser()方法的事务传播机制调整为Propagation.REQUIRES_NEW
9、rollbackFor属性设置错误
示例代码:
@Service public class OrderServiceImpl { @Autowired private OrderMapper orderMapper; @Transactional public int addOrder(Double amount, String address) throws FileNotFoundException { int order = orderMapper.addOrder(amount, address); throw new FileNotFoundException("11111"); } }
@Transactional,在未对rollbackFor做配置的情况下,默认是支持对Runtime和Error异常的回滚的。
而在示例代码中,我们手动的抛出FileNotFountException异常,这是一个IOException异常,是无法回滚异常的。
所以通常情况下,建议指定@Transactional(rollbackFor = Exception.class)的方式进行异常捕获。
10、设置了不支持事务的传播机制
Spring支持了7种传播机制,分别为:
上面不支持事务的传播机制为(如果配置了这三种传播方式的话,在发生异常的时候,事务是不会回滚的):
PROPAGATION_SUPPORTS
PROPAGATION_NOT_SUPPORTED
PROPAGATION_NEVER
示例代码:
@Service public class OrderServiceImpl { @Autowired private OrderMapper orderMapper; @Transactional(rollbackFor = Exception.class, propagation = Propagation.SUPPORTS) public int addOrder(Double amount, String address) throws FileNotFoundException { int order = orderMapper.addOrder(amount, address); throw new FileNotFoundException("11111"); } }