Spring声明式事务@Transactional使用

背景

作为一个后端开发,@Transactional一直在用,但总会碰到各种离奇的不生效的情况,每次都是到处查资料解决。就想写一篇文章整理一下,后面遇到就不用到处找了,有新情况也再补充。

@Transactional

声明式事务

spring支持 编程式事务声明式事务 两种。编程式事务也就是用代码手动控制事务的开始、提交或回滚,这样业务代码就变得不纯粹,功能代码和辅助代码杂糅到一起,并且会有许多重复代码。所以我们一般使用声明式事务。声明式事务一般有两种方式,一是基于tx和aop命名空间的xml配置文件,二是使用@Transactional注解。目前使用比较广泛的就是@Transactional注解。

属性

属性 类型 描述
value、transactionManager String 可选的限定描述符,指定使用的事务管理器
propagation enum: Propagation 可选的事务传播行为设置
isolation enum: Isolation 可选的事务隔离级别设置
readOnly boolean “读写”或“只读”事务,默认false读写
timeout int (in seconds granularity) 事务超时时间设置,默认-1
rollbackFor Class对象数组,必须继承自Throwable 导致事务回滚的异常类数组
rollbackForClassName 类名数组,必须继承自Throwable 导致事务回滚的异常类名字数组
noRollbackFor Class对象数组,必须继承自Throwable 不会导致事务回滚的异常类数组
noRollbackForClassName 类名数组,必须继承自Throwable 不会导致事务回滚的异常类名字数组

value、transactionManager

指定事务管理器的名称,一般用在多数据源应用的事务处理中,用来明确指定使用哪个数据源的事务管理

propagation:事务传播行为【todo 后面写demo代码跑一下验证

  • Propagation.REQUIRED
    • 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。
    • 【外层事务和内层事务是一个事务,要提交一起提交,要回滚一起回滚】
  • Propagation.SUPPORTS
    • 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
    • 【如果有外层事务,那么和Propagation.REQUIRED相同。如果没有外层事务,以非事务的方式运行】
  • Propagation.MANDATORY
    • 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常
    • 【如果有外层事务,那么和Propagation.REQUIRED相同。如果没有外层事务,抛出异常】
  • Propagation.REQUIRES_NEW
    • 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
    • 【外层事务回滚,内部事务正常提交;内部事务回滚,外部事务若对异常进行了捕获,没有再向上抛,则外部事务继续执行】
  • Propagation.NOT_SUPPORTED
    • 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
    • 【外层事务不影响,内层以非事务方式运行】
  • Propagation.NEVER
    • 以非事务方式运行,如果当前存在事务,则抛出异常。
  • Propagation.NESTED
    • 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于Propagation.REQUIRED。
    • 【外部事务回滚,内部事务一定会回滚;内部事务回滚,外部事务继续执行】

Propagation.REQUIRES_NEW、Propagation.NESTED、Propagation.REQUIRED 对比

定义serviceA.methodA()以Propagation.REQUIRED修饰;
定义serviceB.methodB()以表格中三种方式修饰;
methodA中调用methodB

异常状态 Propagation.REQUIRES_NEW
(两个独立事务)
Propagation.NESTED
(B的事务嵌套在A的事务中)
Propagation.REQUIRED
(同一个事务)
methodA抛异常
methodB正常
A回滚,B正常提交 A与B一起回滚 A与B一起回滚
methodA正常
methodB抛异常
1.如果A中捕获B的异常,并没有继续向上抛异常,则B先回滚,A再正常提交;
2.如果A未捕获B的异常,默认则会将B的异常向上抛,则B先回滚,A再回滚
B先回滚,A再正常提交 A与B一起回滚
methodA抛异常
methodB抛异常
B先回滚,A再回滚 A与B一起回滚 A与B一起回滚
methodA正常
methodB正常
B先提交,A再提交 A与B一起提交 A与B一起提交

isolation:事务隔离级别

和数据库的事务隔离级别含义是相同的,只是多了default。区别是isolation指定的是当前连接会话的事务隔离级别,而数据库指的是当前数据库全局的事务隔离级别。当二者不相同时,以当前会话的隔离级别为准。

  • Isolation.DEFAULT
    • 使用数据库默认的事务隔离级别
  • Isolation.READ_UNCOMMITTED
    • 读未提交
  • Isolation.READ_COMMITTED
    • 读已提交
  • Isolation.REPEATABLE_READ
    • 可重复读
  • Isolation.SERIALIZABLE
    • 串行化

readOnly

  • 设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false
  • 如果设置为true却执行了写的操作会发生什么呢?后面写demo跑一下

timeout

  • 设置事务的超时秒数,默认值为-1表示永不超时。超时事务将会回滚。

rollbackFor

  • 该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:
  • 指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)
  • 指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName

  • 该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。
  • 指定单一异常类名称:@Transactional(rollbackForClassName="RuntimeException")
  • 指定多个异常类名称:@Transactional(rollbackForClassName={"RuntimeException","Exception"})

noRollbackFor

  • 该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。

  • 指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)

  • 指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

  • 该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。
  • 指定单一异常类名称:@Transactional(noRollbackForClassName="RuntimeException")
  • 指定多个异常类名称:@Transactional(noRollbackForClassName={"RuntimeException","Exception"})

使用

  • @Transactional要修饰在接口实现类或接口实现方法上,而不是接口类中
  • 方法上注解属性会覆盖类注解上的相同属性
  • 父类的声明的@Transactional会对子类的所有方法进行事务增强;子类覆盖重写父类方式可覆盖其@Transactional中的声明配置
  • 只有来自外部的方法调用才会被AOP代理捕获,也就是,类内部方法调用本类内部的其他方法并不会引起事务行为,即使被调用方法使用@Transactional注解进行修饰
  • @Transactional修饰 public 的方法才起作用
  • 接口中异常(运行时异常)被捕获而没有被抛出,将不会进行事务回滚
     

原理

【todo 我不配,用好了再学习一下】

参考

透彻的掌握 Spring 中 @transactional 的使用

@Transactional

Spring中的@Transactional(rollbackFor = Exception.class)属性详解

关于PROPAGATION_NESTED的理解

Spring事务隔离级别与MySQL设置的级别不一样怎么办

Spring事务隔离级别与Mysql InnoDB事务隔离级别的关系

Spring 使用注解方式进行事务管理

@Transactional 设置嵌套事务不回滚

关于Spring事务的理解(Controller可以使用@Transactional)

spring boot @Transactional注解事务不回滚不起作用无效

springBoot service 事务注解@Transactional不起作用的解决

SpringBoot @Transactional 中捕获异常并回滚解决方法

Springboot中声明事务@Transactional,为何有时候声明了事务报异常数据却不会回滚

声明式事务不回滚@Transactional的避坑正确使用

Spring Boot 中使用 @Transactional 注解配置事务管理

Spring事务的那些坑

Spring @Transactional注解不回滚不起作用无效

spring的@Transactional注解详细用法

猜你喜欢

转载自blog.csdn.net/yxz8102/article/details/109544727