事务的四大特性

  1. 1. 原子性
  2. 2. 一致性
  3. 3. 隔离性
  4. 4. 持久性

事务的传播行为

  1. 在一个事务方法中调用另一个事务的方法才会出现此问题
  2. 类型 外部不存在事务 外部存在事务
  3. 1. REQUIRED(默认) 开启新的事务 融合到外部事务中
  4. 2. SUPPORTS 不开启新的事务 融合到外部事务中
  5. 3. REQUIRES_NEW 开启新的事务 不用外部的事务,创建新的事务
  6. 4. NOT_SUPPORTED 不开启新的事务 不用外部事务
  7. 5. NEVER 不开启新的事务 抛出异常
  8. 6. MANDATORY 抛出异常 融合到外部事务中
  9. 7. NESTED 开启新的事务 融合到外部事务中,Save机制,外层影响内层,内层不会影响外层

事务失效的情况

  1. (注解)事务的原理是通过AOP来实现的,基于动态代理

代理不生效

  1. spring实现动态代理的方式有两种:
  2. 1. 基于接口的jdk动态代理,要求目标代理类需要实现一个接口
  3. 2. 基于CGLIB代理
  4. spring2.0之前,目标如果实现了接口,则使用jdk的动态代理,否则通过cglib实现动态代理
  5. 2.0之后的版本,如果不在配置文件中指定代理方式,默认使用cglib代理(spring.aop.proxy-tartget-class)
  1. 将直接标注在接口方法上

    1. @Transactional直接是支持标注在方法和类上面的,标注在接口上,如果对应接口的代理方式是cglib
    2. 将通过生成子类的方式生成代理对象,将无法解析到@Transactional注解,从而导致事务的失效
  2. 被final 和 static关键字修饰的类或方法

    1. cglib是通过生成目标子类的方式生成代理的,final static修饰后,无法继承父类与父类的方法
  3. 类方法内部调用 ```json 事务的管理是通过代理执行的方式生效的,如果是方法的内部调用则不会走代理逻辑,也就调用不到了

解决办法:

  1. 1. 新创建一个service,将方法迁移过去.(多多少少有点呆)
  2. 2. 在当前类中注入自己,在调用内部方法的时候,通过此对象调用
  3. 3. 通过AopContext.currentProxy()获取代理对象
  1. 4. 当前类没有被spring管理
  2. ```json
  3. 当前类没有被spring管理成为ioc容器中的一个bean

框架或底层不支持

  1. 非public修饰的方法
  2. 多线程调用

    1. 在底层事务的信息是和线程绑定的
    2. 因此在多线程的环境下事务的信息都是独立的,将会导致Spring在接管事务上出现错误
  3. 数据库本身不支持事务

  4. 未开启事务

    错误使用!@Transactional

  5. 错误的传播机制

    1. PROPAGATION_SUPPORTSPROPAGATION_NOT_SUPPORTEDPROPAGATION_NEVER
    2. 如果设置了这三种传播机制,在发生异常的时候,事务是不会回滚的
  6. rollbackFor属性设置错误

    1. 默认情况下事务进回滚运行时异常和Error,不回滚受检异常(例如IOException)
    2. 因此如果方法中抛出IO异常,默认情况下事务也会回滚失败
    3. 我们可以通过@Transactional(rollbackFor = Exception.class)的方式进行全异常捕获。
  7. 异常被内部catch

    1. 如果我们需要对特定的异常进行捕获处理,记得再次将异常抛出,让最外层的事务感知到
  8. 嵌套事务

    1. 根据不同的场景 选择不同的事务传播行为.