0%

事务配置 @Transactional

放在接口上,那么接口的实现类中所有 public 都被 spring 自动加上事务
放在类上,那么当前类以及其下无限级子类中所有 pubilc 方法将被 spring 自动加上事务
注意:@Transaction 只对 public 方法有效

  1. @Transactional 的配置
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    public @interface Transactional {
    // 通过 bean name 指定事务管理器
    @AliasFor("transactionManager")
    String value() default "";

    // 同 value 属性
    @AliasFor("value")
    String transactionManager() default "";

    // 指定传播行为
    Propagation propagation() default Propagation.REQUIRED;

    // 指定隔离级别
    Isolation isolation() default Isolation.DEFAULT;

    // 指定超时时间(单位秒)
    int timeout() default -1;

    // 是否只读事务
    boolean readOnly() default false;

    // 方法在发生指定异常时回滚,默认是所有异常都回滚
    Class<? extends Throwable>[] rollbackFor() default {};

    // 方法在发生指定异常名称时回滚,默认是所有异常都回滚
    String[] rollbackForClassName() default {};

    // 方法在发生指定异常时不回滚,默认是所有异常都回滚
    Class<? extends Throwable>[] noRollbackFor() default {};

    // 方法在发生指定异常名称时不回滚,默认是所有异常都回滚
    String[] noRollbackForClassName() default {};
    }
  2. Isolation 隔离级别
    • DEFAULT——数据库默认隔离级别,MySQL 是可重复读,Oracle 是已提交读
    • READ_UNCOMMITTED——未提交读:事务读取其他事务未提交的数据
    • READ_COMMITTED——已提交读:事务读取最新的其他事务已提交的数据
    • REPEATABLE_READ——可重复读:事务读取该事务开始的时间点的其他事务已提交的数据
    • SERIALIZABLE——可序列化:所有事务只能一个接一个串行执行,不能并发

    可能发生的问题:

    • 脏读——事务 T1 读取了已被事务 T2 更新但还没有提交的数据,若 T2 回滚,T1 读取到的就是无效内容
    • 不可重复读——事务 T1 读取一个数据两次,在第一次和第二次之间,T2 更新了该数据,导致 T1 第二次读取到的数据不同
    • 幻读——事务 T1 读取若干行数据两次,在第一次和第二次之间,T2 新增或删除该数据集,导致 T1 第二次读取到的数据条数不同

    幻读与不可重复读之间的区别是幻读强调的是新增或删除,而不可重复读强调的是修改。


    类型 脏读 不可重复读 幻读
    未提交读
    已提交读 ×
    可重复读 × ×
    可序列化 × × ×
  3. Propagation 传播行为
    • REQUIRED——默认传播行为,需要事务,如果当前存在事务,就沿用当前事务,否则新建一个事务运行子方法
    • SUPPORTS——支持事务,如果当前存在事务,就沿用当前事务,如果不存在,则继续采用无事务的方式运行子方法
    • MANDATORY——必须使用事务,如果当前没有事务,则会抛出异常,如果存在当前事务 就沿用当前事务
    • REQUIRES_NEW——无论当前事务是否存在,都会创建新事务运行方法
    • NOT_SUPPORTED——不支持事务,当前存在事务时,将挂起事务,运行方法
    • NEVER——不支持事务,如果当前方法存在事务,则抛出异常,否则继续使用无事务机制运行
    • NESTED——外围主事务回滚,子事务一定回滚,而内部子事务可以单独回滚而不影响外围主事务和其他子事务。