Files
rikako-note/spring/Spring core/Spring Data Access.md
2022-09-20 00:54:11 +08:00

9.0 KiB
Raw Blame History

Spring Data Access

  • Spring事务

    • 本地事务和全局事务:
      • 全局事务:全局事务允许使用多个事务资源,应用服务器来对全局事务进行管理
      • 本地事务:本地事务无法管理多个事务资源
    • 本地事务和全局事务的优缺点
      • 全局事务的使用需要和服务器环境相绑定,降低了代码的重用性
      • 本地事务无法使用多个事务资源无法通过JTA等框架来对多个事务资源进行管理无法使用分布式事务
  • 声明式事务

    • Spring中声明式事务是通过AOP来实现的

    • 在声明式事务中,可以为方法级的粒度指定事务行为

    • 声明式事务的回滚规则:

      • 在Spring声明式事务中可以为事务指定回滚规则即指定针对哪些异常事务会自动执行回滚操作
      • 在默认情况下只有抛出unchecked异常通常为RuntimeException声明式事务才会进行回滚
    • 声明式事务的实现细节:

      • 声明式事务通过aop代理实现并且事务的advice是通过xml元数据配置来驱动的
      • aop和事务元数据联合产生了一个aop代理对象并且该代理对象通过使用TransactionInterceptor和TransactionManager来实现事务
      • @Transactional通常和线程绑定的事务一起工作线程绑定的事务由PlatformTransactionManager管理。@Transactional会将事务暴露给当前执行线程中所有的dao操作
    • 声明式事务的回滚:

      • 在Spring事务中推荐让事务回滚的方式是在事务执行的方法中抛出一个异常
      • Spring事务在默认情况下只会针对unchecked异常RuntimeException进行回滚对于ErrorSpring事务也会执行回滚操作
      • checked异常并不会导致事务的回滚操作可以注册rollback rule来指定对特定的异常包括checked异常进行回滚操作
    • rollback rule

      • 回滚规则rollback rule通常用来指定当一个异常被抛出时是否为该异常执行事务的回滚操作
      • 在@Transactional注解中可以指定rollbackFor/noRollbackFor、rollbackForClassName/noRollbackForClassName来指定为那些异常类执行回滚操作

      当指定rollbackFor属性为checked异常时如rollbackFor=FileNotFoundException.class)此时指定的异常不会覆盖其默认行为为RuntimeException和Error异常执行回滚操作
      故而指定后其默认会为Error、RuntimeException、FileNotFoundException三类异常执行回滚操作

      @Transactional(rollbackFor={MyException.class})
      public void myOperation() {
        // ...
      }
      
  • 基于注解的声明式事务

    • @Transactional既可以作用于类上也可以作用于方法上。当作用于类上时该声明类中所有的方法都会被声明是事务的该类子类中所有的方法也都是事务的
    • @Transactional是可以继承的被@Inherited元注解修饰。

    @Inherited类是元注解用来修饰注解类。如果一个注解类被@Inherited注解标识那么在对class查询该注解类时如果当前class没有声明该注解将会在当前class的父类中查找该注解依次递归。直到在父类中找到该注解或是到达继承结构的顶部Object类。@Inherited标注的注解仅能在类继承中有效如注解被标注在接口上那么将@Inherited标注的注解将不会被递归查询到。

    • 并且class级别的@Transactional并不应用在从父类继承的方法上即若一个类被@Transactional注解标注并且该类从父类继承方法那么该类从父类继承的方法并不会被看作是事务的除非在该类中重新声明继承的方法。
    • 通过在Configuration类上注解@EnableTransactionManagement配合@Transactional可以将一个bean对象声明是事务的
    • 当基于标准spring配置时应该仅将@Transactional注解标注于public方法当将@Transactional注解标注于非public方法时无效
    • 在Spring中仅推荐将@Transactional注解应用于类上不推荐将其应用在接口接口方法上。如果将其应用在接口上那么该事务配置仅仅对基于接口的动态代理有效对基于class的代理无效。
    • 当类级别和方法级别都设置了@Transactional注解时方法级别的设置会优先被使用
  • @Transactional注解的配置

    • 事务的传播: 默认情况下,@Transactional的propagation属性是PROPAGATION_REQUIRED
    • 事务的隔离级别: 默认情况下,@Transactional的isolation属性是ISOLATION_DEFAULT使用数据库默认的隔离级别
    • readOnly 默认情况下,@Transactional的readOnly属性是false默认事务是可读写的
    • timeout 默认况下下,@Transactional的超时属性取决于底层的事务系统如果底层事务系统不支持timeout则timeout属性为none
    • rollbackFor 默认情况下,@Transactional会针对unchecked异常和Error进行回滚操作
    • transactionManager 默认情况下,@Transactional注解会使用项目中默认的事务管理器即bean name为transactionManager的事务管理器。可以为@Transactional注解指定value属性或是transactionManager属性来指定想要采用的事务管理器的bean name或是qualifier
  • Transaction Propagation

    • PROPAGATION.REQUIRED

      • 在Spring中事务的传播行为默认是PROPAGATION_REQUIRED默认情况下该选项会强制的要求一个物理事务
        • 如果当前作用域中不存在事务,那么会创建一个新的事务
        • 如果当前作用域的外层作用域已经存在事务,那么会加入到当前作用域的事务中去
      • 在Spring中默认情况下当嵌套事务加入到外层的事务中时会忽略内层事务定义的隔离级别、timeout设置和读写标志等。

      如果想要对外层事务进行验证可以手动将事务管理器的validateExistingTransaction属性设置为true。这样当加入到一个隔离级别与内层事务完全不同的外层事务中时该加入操作会被拒绝。在该设置下如果read-write内层事务想要加入到外层的read-only事务中时该加入操作也会被拒绝。

      • 在事务传播行为被设置为PROPAGATION_REQUIRED的情况下会为每个被设置事务的方法创建一个逻辑的事务作用域。各个逻辑事务作用域之间都是相互独立的在不同逻辑事务作用域之间都可以独立设置事务的rollback-only属性。但是在PROPAGATION_REQUIRED的情况下内层事务和外层事务都映射到同一个物理事务内层事务加入到外层事务中故而在内层逻辑事务中为物理事务设置rollback-only会切实影响到外层事务的提交。
      • 当事务传播行为被设置为PROPAGATION_REQUIRED时如果内层事务设置了rollback-only标记那么会导致外层物理事务的回滚。当外层事务尝试提交并失败回滚后会抛出一个UnexceptedRollbackException异常外层事务commit方法的调用者会接受到该UnexceptedRollbackException代表内层发生了非预期的回滚操作
    • PROPAGATION.REQUIRES_NEW

      • 相对于PROPAGATION_REQUIREDPROPAGATION.REQUIRES_NEW传播行为会一直使用独立的物理事务而不会尝试区加入外部已经存在的物理事务。
      • 对于PROPAGATION_NEW,其内层事务和外层事务都可以独立的提交或回滚,内层事务的回滚并不会导致外层事务的回滚。
      • 将事务传播行为设置为PROPAGATION.REQUIRES_NEW时内层事务可以独立定义自己的隔离级别、timeout值、read-only属性而不必继承外部事务的这些属性。在PROPAGATION_REQUIRED中内部事务自定义这些属性将会被忽略内部事务加入外部事务后会采用外部事务的设置。
    • PROPAGATION.NESTED

      • 和PROPAGATION_REQUIRED类似PROPAGATION_NESTED同样也只有一个物理事务。但是其支持多个savepoint存档点该物理事务可以回滚到特定的存档点而非必须回滚整个事务。
      • 由于PROPAGATION_NESTED对存档点的支持故而在PROPAGATION_NESTED条件下可以进行部分回滚。内层事务的回滚操作并不会造成外部事务的回滚内层事务回滚后外层事务仍然能够继续执行和提交。

      由于PROPAGATION_NESTED需要JDBC savepoint存档点的支持故而该设置仅仅对JDBC事务资源有效。

    当事务被回滚之后,当前事务无法再被提交,故而:
    若在子事务中已经回滚子事务传播行为为required那么父事务的状态已经被回滚即使父事务捕获子事务抛出的异常那么在捕获异常之后执行的sql操作也不会被提交到数据库中父事务状态处于已回滚无法再次提交
    但是当子事务传播行为为nested时子事务虽然和父事务共用一个事务子事务回滚时只会回滚到子事务开启之前的存档点父事务在捕获子事务抛出异常之后执行的sql语句仍然可以被提交