一篇文章学会使用@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

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


目录
相关文章
|
7月前
|
XML Java 关系型数据库
@Transactional注解的失效场景
@Transactional注解的失效场景
120 1
|
7月前
|
Java 编译器 数据库
在事务注解@Transactional中指定rollbackFor
在事务注解@Transactional中指定rollbackFor
63 0
|
2月前
|
监控 Java 数据库
Spring事务中的@Transactional注解剖析
通过上述分析,可以看到 `@Transactional`注解在Spring框架中扮演着关键角色,它简化了事务管理的复杂度,让开发者能够更加专注于业务逻辑本身。合理运用并理解其背后的机制,对于构建稳定、高效的Java企业应用至关重要。
72 0
|
6月前
|
SQL Java 数据库
Transactional注解讲解及使用
事务是数据库操作的一组集合,它作为一个工作单元,要求所有操作要么全部成功,要么全部失败。事务的四个基本特性是原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
|
7月前
|
Java 编译器 Spring
@transactional注解失效情况
@transactional注解失效情况
|
SQL Java 数据库连接
@Transactional
@Transactional
116 0
|
Java 数据库 Spring
@Transactional注解超详细
@Transactional注解超详细
954 0
|
Java 数据库 Spring
@Transactional 注解失效问题
@Transactional 注解失效问题
112 0
|
数据库
Transactional注解不生效案例
Transactional注解不生效案例
150 0
Transactional注解不生效案例
|
存储 Oracle 安全