一篇文章学会使用@Transactional

简介: 一篇文章学会使用@Transactional

@Transactional

参考文档

https://docs.spring.io/spring-framework/docs/4.3.13.RELEASE/spring-framework-reference/htmlsingle/#transaction-declarative-annotations

作用范围

  • 方法
    当类配置了@Transactional ,方法也配置了@Transactional,方法的事务会覆盖类的事务属性信息。

  • 当把 @Transactional 注解作用在类上面时,表示该类的所有public方法都配置相同的事务属性信息。
  • 接口
    不推荐配置在接口,因为一旦配置配置在 Interface上并且配置了Spring AOP 使用CGLib动态代理,将会导致@Transactional 注解失效

注解属性有哪些

  • Propagation 事务的传播属性
  • REQUIRED 默认属性
    支持当前事务,如果存在就加入当前事务,如果当前不存在事务就创建一个新事务
    如果A方法和B方法都添加了注解,且在默认事务传播行为下,两个事务会合并成一个事务
  • SUPPORTS
    如果当前存在事务,则加入该事务。如果当前不存在事务,在以非事务的方式运行
  • MANDATORY
    如果当前存在事务,则加入该事务。如果当前不存在事务,在抛出异常
  • REQUIRES_NEW
    开启一个新事务,如果当前存在事务,则暂停当前事务
    类A中的a方法使用默认的Propagation.REQUIRED模式,类B中的b方法加上Propagation.REQUIRED_NEW模式,然后在a方法中调用b方法操作数据库,a方法发生异常后, b方法不会回滚。因为b方法的Propagation.REQUIRED_NEW模式会暂停a方法的事务
  • NOT_SUPPORTED
    以非事务的方式运行,如果当前存在事务,暂停当前的事务
  • NEVER
    以非事务的方式运行,如果当前存在事务,则抛出异常
  • NESTED
    如果当前存在事务,则在嵌套事务中执行。效果与REQUIRED类似
  • isolation 事务的隔离级别,默认值
  • DEEAULT
    使用底层数据库的默认隔离级别
  • READ_UNCOMMITED
    读未提交,会有脏读,不可重复读,幻象读发生。由一个事务更改的行可以在未提交前被另一个事务读取(脏读),如果事务被回滚,则第二个事务将检索到无效的行
  • READ_COMMITED
    读提交,解决脏读,但是还会有不可重复读,幻读现象发生。仅允许读取已提交事务的信息
  • REPEATABLE_READ
    可重复读,可以防止脏读和不可重复读,但是幻象读还会发生。可以保证同一个事务多次读取数据都是一致的
  • SERIALIZABLE
    串行化,最高级别,事务一个一个的执行,效率最低,隔离级别最高,能够解决脏读,幻读,不可重复读
  • timeout 事务的超时时间
    默认值-1,超过该时间限制,但是事务还没有完成,则自动回滚事务
  • readOnly 只读事务
    默认false,对于不需要事务的方法可以设置为true
  • rollbackFor
    定义一个或者多个异常回滚的类型,它们必须是Throwable的子类,默认会在RuntimeException和Error上回滚,对于非检查异常不会进行回滚
  • rollbackForClassName
    与rollbackFor类似,只是值为字符串类型的异常类名称。例如值为ServletException则会匹配javax.servlet.ServletException
  • noRollbackFor
    指定一个或者多个异常不进行异常回滚,值与rollbackFor类型一样,作用相反
  • noRollbackForClassName
    指定一个或者多个进行异常回滚操作,值与rollbackForClassName类型一样,作用相反

注解失效的场景有哪些

  • 注解应用在非public修饰的方法上
    需要注意的一点是注解在private,protected方法上事务无效,但是不会报错
AbstractFallbackTransactionAttributeSource.computeTransactionAttribute
 //  方法会检查是否是public方法,
    // Don't allow no-public methods as required.
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      return null;
    }
  • @Transactional 注解属性propagation 设置错误
  • SUPPORTS:如果当前存在事务就加入该事务,如果当前不存在事务再以非事务的方式运行
  • NOT_SUPPORTS: 以非事务的方式运行,如果当前存在事务,暂停当前事务
  • NEVER:以非事务的方式运行,如果当前存在事务,则抛出异常
  • @Transactional 注解属性rollBackFor设置错误
    rollBackFor指定触发事务回滚的异常类型,默认是RuntimeException和Error会触发回滚,其它的异常不会出发回滚事务,如果希望自定义的异常出发回滚需要指定自定义的异常类型
@Transactional(rollbackFor= MyException.class)
// 源码如下
  public int getDepth(Throwable ex) {
    return getDepth(ex.getClass(), 0);
  }
  private int getDepth(Class<?> exceptionClass, int depth) {
    if (exceptionClass.getName().contains(this.exceptionName)) {
      // Found it!
      return depth;
    }
    // If we've gone as far as we can go and haven't found it...
    if (exceptionClass == Throwable.class) {
      return -1;
    }
    return getDepth(exceptionClass.getSuperclass(), depth + 1);
  }
  • 同类方法调用
    此时方法B是不会触发事务回滚的,因为事务的方法只有被当前类之外的方法调用时才会有Spring的代理对象管理
public class Test{
  public void A(){
    B();
  }
  @Transactional
  public void B() throw Exception{
    // insert
  }
}
  • 异常被catch吃掉
public void A(){
    try{
      B();
    }catch(Exception e){
      log.error(e);
    }
  
  }
  @Transactional
  public void B(){
    // insert
  }
  • 数据库引擎本身不支持事务
    MySQL 本身已经默认InnoDB引擎,是支持事务的,MyISam不支持事务,现在用的基本也没有了,一旦数据库使用不支持事务的引擎,那注解从根本上也就不管了

测试事务是否生效记录

测试方法为类A方法A调用类B方法B,携带注解为@Transactionsal(rollbackFor=Exception.class)

测试代码结构,通过改变异常位置,注解位置测试

public class A{
  @Autowired
  private B b;
  
  public void A() {
    b.B();
  }
}
public class B{
   @Autowired
    private TestSysMapper testSysMapper;
    @Transactional(rollbackFor = Exception.class)
    public void B() {
        TestSys testSys = new TestSys();
        testSys.setId(1);
        testSys.setName("name1");
        testSysMapper.insert(testSys);
        if (true){
            throw new RuntimeException();
        }
    }
}

测试说明: 数据插入说明事务未生效,未插入数据说明事务成功

默认测试注解形式为:@Transactional(rollbackFor = Exception.class)

A方法是否带注解 B方法是否带注解 异常位置 数据是否插入
不带 类B方法B false
不带 类B方法B false
不带 类A方法A true
不带 类A方法A false
带@Transactional(rollbackFor = Exception.class) 带@Transactional(rollbackFor = Exception.class) 类A方法A false
带@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class,propagation = Propagation.SUPPORTS) 类A方法A false
带@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class,propagation = Propagation.MANDATORY) 类A方法A false
带@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRES_NEW) 类A方法A true
带@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class,propagation = Propagation.NOT_SUPPORTED) 类A方法A True
带@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class,propagation = Propagation.NEVER) 类A方法A false
带@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class,propagation = Propagation.NESTED) 类A方法A false

感觉有帮助可以关注一下公众号获取最新文章输出


目录
相关文章
|
Shell Android开发 开发者
adb简介及常用命令总结
adb(Android Debug Bridge),安卓平台调试桥,是连接Android手机与PC端的桥梁,通过adb可以管理、操作模拟器和设备,如安装软件、查看设备软硬件参数、系统升级、运行shell命令等。 简单总结主要功能有: 1、运行设备的shell(命令行) 2、管理模拟器 3、计算机和设备之间上传/下载文件 4、将本地apk软件安装至模拟器或android设备
1860 0
|
4月前
|
人工智能 监控 API
全网跪求的抢票神器!用 CodeBuddy 联动魔搭 MCP,我把 12306 抢票系统玩明白了
CodeBuddy 作为智能编程领域的佼佼者,无需用户具备深厚的编程知识,就能依据用户需求迅速生成高效代码。在票务信息获取方面,它巧妙地构建起与两款 MCP 顺畅交互的桥梁。通过简洁直观的指令输入,CodeBuddy 将用户对票务信息的需求精准转化为机器可理解的语言,为后续获取信息的流程奠定坚实基础。
284 2
|
Web App开发 前端开发 JavaScript
控制台出现报错DevTools failed to load source map: Could not load content for chrome-extension://的原因及解决方案
控制台出现报错DevTools failed to load source map: Could not load content for chrome-extension://的原因及解决方案
827 0
控制台出现报错DevTools failed to load source map: Could not load content for chrome-extension://的原因及解决方案
|
11月前
|
存储 JavaScript 前端开发
深入理解JavaScript中的事件循环(Event Loop):机制与实现
【10月更文挑战第12天】深入理解JavaScript中的事件循环(Event Loop):机制与实现
391 3
|
10月前
|
Java 数据库连接 数据库
如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面
本文介绍了如何构建高效稳定的Java数据库连接池,涵盖连接池配置、并发控制和异常处理等方面。通过合理配置初始连接数、最大连接数和空闲连接超时时间,确保系统性能和稳定性。文章还探讨了同步阻塞、异步回调和信号量等并发控制策略,并提供了异常处理的最佳实践。最后,给出了一个简单的连接池示例代码,并推荐使用成熟的连接池框架(如HikariCP、C3P0)以简化开发。
270 2
|
缓存 NoSQL Java
在 Spring Boot 应用中使用 Spring Cache 和 Redis 实现数据查询的缓存功能
在 Spring Boot 应用中使用 Spring Cache 和 Redis 实现数据查询的缓存功能
674 0
|
11月前
|
监控 Java 数据库
Spring事务中的@Transactional注解剖析
通过上述分析,可以看到 `@Transactional`注解在Spring框架中扮演着关键角色,它简化了事务管理的复杂度,让开发者能够更加专注于业务逻辑本身。合理运用并理解其背后的机制,对于构建稳定、高效的Java企业应用至关重要。
344 0
|
SQL 关系型数据库 MySQL
配置MySQL主从复制(一主一从)
配置MySQL主从复制(一主一从)
225 1
|
SQL Java 数据库
@Transactional 用法和原理
@Transactional 用法和原理
|
存储 NoSQL 关系型数据库
【MongoDB 专栏】MongoDB 的 ACID 事务支持
【5月更文挑战第11天】MongoDB,作为流行的非关系型数据库,逐步强化ACID事务支持,确保数据操作可靠性。事务包括原子性、一致性、隔离性和持久性四个特性。MongoDB通过多文档事务和锁机制实现ACID,适用于复杂操作、分布式协调和高一致性业务。然而,使用时注意性能影响、事务范围、错误处理及版本兼容性。随着技术进步,MongoDB将持续优化事务处理,应对更多复杂业务场景,为数据库领域带来创新与机遇。理解并恰当运用事务特性对构建高效应用至关重要。
363 0
【MongoDB 专栏】MongoDB 的 ACID 事务支持