• Java-Spring事务


    事务

    • 什么是事务?

    一系列操作要么全部完成,要么全部失败.

    • 事务的特新(ACID)?

      1. 原子性:事务最小的执行单位,不可分割的,要么全部完成,要么都不起作用.
      2. 一致性:事务执行前后,数据保持一致.
      3. 隔离性:并发时,一个事务不能影响另一个事务的执行.
      4. 持久性:事务一旦提交就是永久的,哪怕数据库故障也不会有影响.
      

    Spring中的事务

    程序是否支持事务取决于数据库,以Mysql为例,如果是myisam引擎的话,是不支持事务的.在Spring中事务有2种,编程式事务,声明式事务.

    • 编程式事务.

    使用TransactionTemplate编写事务代码,当捕捉到异常时,执行回滚操作.

    transactionTemplate.execute(new TransactionCallbackWithoutResult() {
                @Override
                protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                    try {
                        // ....  业务代码
                    } catch (Exception e){
                        //回滚
                        transactionStatus.setRollbackOnly();
                    }
                }
            });
    
    • 声明式事务.

    推荐使用声明式事务,代码侵入低. @Transactional注解,基于AOP实现.

    @Transactional(propagation=propagation.PROPAGATION_REQUIRED)
    public void aMethod {
      //do something
      B b = new B();
      C c = new C();
      b.bMethod();
      c.cMethod();
    }
    
    • 事务传播行为?

    当多个事务存在时,如何处理事务.

      1. TransactionDefinition.PROPAGATION_REQUIRED
    
      默认值,当前存在事务就加入该事务,不存在事务就新建事务.
      注意:aMethod和bMethod只要有一个回滚,整个事务均回滚.即外部事务被PROPAGATION_REQUIRED修饰时,内部所有也被PROPAGATION_REQUIRED修饰的事务都是一个事务.
    
    //代码
    Class A {
        @Transactional(propagation=propagation.PROPAGATION_REQUIRED)
        public void aMethod {
            //do something
            B b = new B();
            b.bMethod();
        }
    }
    
    Class B {
        @Transactional(propagation=propagation.PROPAGATION_REQUIRED)
        public void bMethod {
           //do something
        }
    }
    
      2. TransactionDefinition.PROPAGATION_REQUIRES_NEW
    
      无论当前是否存在事务,被其修饰的方法都会开启新的事务,且事务互相独立.
      注意:如下,使其修饰bMethod,aMethod不变;若aMethod异常回滚,bMethod不受影响.但是bMethod回滚,aMethod也会回滚.
    
    //代码
    Class A {
        @Transactional(propagation=propagation.PROPAGATION_REQUIRED)
        public void aMethod {
            //do something
            B b = new B();
            b.bMethod();
        }
    }
    
    Class B {
        @Transactional(propagation=propagation.REQUIRES_NEW)
        public void bMethod {
           //do something
        }
    }
    
      3. TransactionDefinition.PROPAGATION_NESTED
    
      如果外部没有事务,那么内部事务新建事务且互相独立互不影响.
      如果外部有事务,那么内部事务属于外部事务的子事务,外部事务回滚,子事务回滚;子事务回滚不会影响外部事务.
      注意:如果 aMethod() 回滚的话,bMethod()和bMethod2()都要回滚,而bMethod()回滚的话,并不会造成 aMethod() 和bMethod()回滚。
    
    //代码
    Class A {
        @Transactional(propagation=propagation.PROPAGATION_REQUIRED)
        public void aMethod {
            //do something
            B b = new B();
            b.bMethod();
            b.bMethod2();
        }
    }
    
    Class B {
        @Transactional(propagation=propagation.PROPAGATION_NESTED)
        public void bMethod {
           //do something
        }
        @Transactional(propagation=propagation.PROPAGATION_NESTED)
        public void bMethod2 {
           //do something
        }
    }
    
      4. TransactionDefinition.PROPAGATION_MANDATORY
    
      如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 基本不用.
    
    • 以下配置发生错误也不会回滚

      1. TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
      2. TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
      3. TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
      
    • 事务超时属性?

      所谓事务超时,就是指一个事务所允许执行的最长时间,如果超过该时间限制但事务还没有完成,则自动回滚事务。在 TransactionDefinition 中以 int 的值来表示超时时间,其单位是秒,默认值为-1。
      
    • 事务只读属性?

      对于只有查询操作的事务,可以设置为readonly,即只读事务,一般用于多条数据库查询.
      
    • 为什么只读还要加事务?

      以MySQL的innodb为例: 
      
      MySQL 默认对每一个新建立的连接都启用了autocommit模式。在该模式下,每一个发送到 MySQL 服务器的sql语句都会在一个单独的事务中进行处理,执行结束后会自动提交事务,并开启一个新的事务。
      
    1. 加Transactional:

      所有的查询sql会放到一个事务中.

    2. 不加Transactional:

      每条sql会开启一个单独的事务,中间被其它事务改了数据,都会实时读取到最新值。

    • 什么时候使用只读事务?
    1. 如果你一次执行单条查询语句,则没有必要启用事务支持,数据库默认支持 SQL 执行期间的读一致性.

    2. 如果你一次执行多条查询语句,例如统计查询,报表查询,在这种场景下,多条查询 SQL 必须保证整体的读一致性,否则,在两条SQL查询之间,数据被其他用户改变,则该次整体的统计查询将会出现读数据不一致的状态.

    • 事务回滚规则?

    默认回滚 RuntimeException的子类,也可以自己指定

    @Transactional(rollbackFor= MyException.class)
    
    • @Transactional 注解原理
    如果一个类或者一个类中的 public 方法上被标注@Transactional 注解的话,Spring 容器就会在启动的时候
    为其创建一个代理类,在调用被@Transactional 注解的 public 方法的时候,实际调用的是,
    TransactionInterceptor 类中的 invoke()方法。这个方法的作用就是在目标方法之前开启事务,方法执行过程中如果遇到异常的时候回滚事务,方法调用完成之后提交事务。
    
    • @Transactional 注解失效?
    1. @Transactional 注解只有作用到 public 方法上事务才生效,不推荐在接口上使用;
    2. 避免同一个类中调用 @Transactional 注解的方法,这样会导致事务失效;
    3. 正确的设置 @Transactional 的 rollbackFor 和 propagation 属性,否则事务可能会回滚失败

    转自JavaGuide面试突击版

  • 相关阅读:
    知识收集
    代码片_笔记
    北理工软件学院2016程序设计方法与实践
    内存的初始化与清零问题
    LeetCode第七题
    KMP算法C代码
    在64位Linux上安装32位gmp大数库
    ASN1编码中的OID
    迷宫问题
    64位linux编译32位程序
  • 原文地址:https://www.cnblogs.com/qifengle1412/p/12879540.html
Copyright © 2020-2023  润新知