特别说明:事务分为声明式事务、编程式事务 本会最下方会额外介绍两者的区别!

本教程来源于:https://mp.weixin.qq.com/s/MzfOq0VGqtDMaxyvp8SOnA

事务包含的范围越小越好。

1、spring要求被代理方法必须是public修饰。

spring事务底层使用了aop,也就是通过jdk动态代理或者cglib,帮我们生成了代理类,在代理类中实现的事务功能。 如果方法被static、final修饰了,因为类加载机制就无法通过代理对象帮我们操作了。

2、业务实现多线程处理导致事务失效

首先明确一点,事务是指同一个数据库连接。多线程执行业务,每个线程拿到的数据库连接是不一样的,如果线程A出现了异常,触发回滚,那么线程B是不会触发回滚的!

3、方法内部调用,不是不允许调用,而是事务失效

同一个Service 直接调用自身其他方法

推荐解决方式一:自己注入自己,然后通过IOC的对象指向方法

推荐解决方式二:使用AopContext 代理对象 执行方法

如: ((ServiceA)AopContext.currentProxy()).doSave(user);

4、未被spring管理

事务是由SpringIOC管理的。@Controller、@Service、@Component、@Repository等注解,可以自动实现bean实例化和依赖注入的功能。也就是说有这些注解的类,是支持事务的。

如:@Service注解丢失:则意味此对象不被IOC容器锁管理,事务是Spring的,不被管理的对象肯定不会触发事务!

5、数据库引擎不支持事务

MyISAM表不支持事务,目前常用的都是InnerDB 数据库引擎了

6、自己吞了异常

事务只有异常才会回滚,自己catch了异常,则不会回滚

7、异常对象错误

Spring默认只会回滚RuntimeException(运行时异常),如果自己 throw new Exception(XXXX); 则不回滚,建议:

 # catch里执行,触发强制回滚
 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();

8、自定义了回滚异常

@Transactional(rollbackFor = XXXX.class) 这就声明了此回滚触发必须是XXXX异常

如果正常情况触发的异常不是XXXX,那么久不会被事务所捕捉到,触发回滚!

  • 阿里巴巴开发者规范中,还是要求开发者重新指定该参数。因为如果使用默认值,一旦程序抛出了Exception,事务不会回滚,这会出现很大的bug。所以,建议一般情况下,将该参数设置成:Exception或Throwable。 如:@Transactional(rollbackFor = Exception.class)

9、嵌套回滚异常

ServiceA 调用ServiceB的业务,ServiceB调用过程出现了异常,如果ServiceB没有异常处理,那么异常就会抛给ServiceA。如果ServiceA中一个try catch 包含了多个DML语句,那么ServiceA抓到了ServiceB的异常,就会是的ServiceA的所有SQL业务也将会全部回滚!

声明式事务 与 编程式事务对比

声明式事务:

  • 一个注解搞定@Transactional
  • 开发方便、省事

编程式事务:

  • spring还提供了另外一种创建事务的方式 TransactionTemplate
  • 事务粒度小
  • 避免由于spring aop问题,导致事务失效的问题

编程式事务伪代码


   // 注入spring 指定的编程式事务对象
   @Autowired
   private TransactionTemplate transactionTemplate;


         // 编程式事务具体局部代码使用
         transactionTemplate.execute((status) => {
            // todo 调用service1
            addData1();
            // todo 调用service2
            updateData2();
            // todo 如果都没有啥问题,返回true,提交事务,如果返回false,回滚事务
            return Boolean.TRUE;
         })