【小家Spring】Spring事务相关的基础类打点(spring-jdbc和spring-tx两个jar),着重讲解AnnotationTransactionAttributeSource(上)

简介: 【小家Spring】Spring事务相关的基础类打点(spring-jdbc和spring-tx两个jar),着重讲解AnnotationTransactionAttributeSource(上)

前言


本篇博文定位为为事务相关的其余博文的工具博文,属于Spring事务相关的基础类的打点、扫盲篇。


因为Spring的事务属于它非常非常重要的一块,因此内部的一些核心类、核心API有必要做个系统的了解,才能更好的了解到其深意。


TransactionAttribute


这个接口是在TransactionDefinition的基础上的扩展

// 它继承自TransactionDefinition ,所有可以定义事务的基础属性
public interface TransactionAttribute extends TransactionDefinition {
   // 返回与此事务属性关联的限定符值
  //@since 3.0
  @Nullable
  String getQualifier();
  // Should we roll back on the given exception?
  boolean rollbackOn(Throwable ex);
}


image.png


它的主要实现类有:DefaultTransactionAttribute、RuleBasedTransactionAttribute、DelegatingTransactionAttribute


DefaultTransactionAttribute



默认的事务属性实现,也是最常用的一个实现。


// 它继承自DefaultTransactionDefinition 
public class DefaultTransactionAttribute extends DefaultTransactionDefinition implements TransactionAttribute {
  @Nullable
  private String qualifier;
  @Nullable
  private String descriptor;
  // 你自己也可以自定义一个TransactionAttribute other 来替换掉一些默认行为
  public DefaultTransactionAttribute() {
    super();
  }
  public DefaultTransactionAttribute(TransactionAttribute other) {
    super(other);
  }
  // @since 3.0
  public void setQualifier(@Nullable String qualifier) {
    this.qualifier = qualifier;
  }
  @Override
  @Nullable
  public String getQualifier() {
    return this.qualifier;
  }
  ...
  // 可以清晰的看到:默认只回滚RuntimeException 或者 Error(比如OOM这种)
  @Override
  public boolean rollbackOn(Throwable ex) {
    return (ex instanceof RuntimeException || ex instanceof Error);
  }
}

RuleBasedTransactionAttribute


这个在基础实现的基础上扩展了一下,扩展了一些规则。

public class RuleBasedTransactionAttribute extends DefaultTransactionAttribute implements Serializable {
  /** Prefix for rollback-on-exception rules in description strings. */
  public static final String PREFIX_ROLLBACK_RULE = "-";
  /** Prefix for commit-on-exception rules in description strings. */
  public static final String PREFIX_COMMIT_RULE = "+";
  // RollbackRuleAttribute:它是个实体类,确定给定异常是否应导致回滚的规则
  // 相当于封装了这个规则的一个实体,内部封装一个异常  提供一个实例变量: 这个变量相当于回滚规则为只回滚RuntimeException
  // public static final RollbackRuleAttribute ROLLBACK_ON_RUNTIME_EXCEPTIONS = new RollbackRuleAttribute(RuntimeException.class);
  // 所以此类最重要的一个属性,就是这个,它能维护多种回滚的规则~~~~
  @Nullable
  private List<RollbackRuleAttribute> rollbackRules;
  ...
  public List<RollbackRuleAttribute> getRollbackRules() {
    if (this.rollbackRules == null) {
      this.rollbackRules = new LinkedList<>();
    }
    return this.rollbackRules;
  }
  // 核心逻辑输入,复写了父类的rollbackOn方法。也就是看看当前异常是否需要回滚呢???
  @Override
  public boolean rollbackOn(Throwable ex) {
    RollbackRuleAttribute winner = null;
    int deepest = Integer.MAX_VALUE;
    // 这里getDepth()就是去看看异常栈里面  该类型的异常处于啥位置。
    // 这里用了Integer的最大值,基本相当于不管异常有多深,遇上此异常都应该回滚喽,也就是找到这个winnner了~~~~~
    if (this.rollbackRules != null) {
      for (RollbackRuleAttribute rule : this.rollbackRules) {
        int depth = rule.getDepth(ex);
        if (depth >= 0 && depth < deepest) {
          deepest = depth;
          winner = rule;
        }
      }
    }
    // User superclass behavior (rollback on unchecked) if no rule matches.
    // 这句相当于:如果你没有指定回滚规则,那就交给父类吧(只回滚RuntimeException和Error类型)
    if (winner == null) {
      return super.rollbackOn(ex);
    }
    // 最终只要找到了,但是不是NoRollbackRuleAttribute类型就成`~~~~
    return !(winner instanceof NoRollbackRuleAttribute);
  }
}


DelegatingTransactionAttribute

很显然,它就是一个简单的代理,内部持有一个TransactionAttribute的引用。自己也是个抽象类,没做啥事,此处略过。它也继承自:DelegatingTransactionDefinition


TransactionDefinition


事务的定义,上面已经介绍了一个重要分支:TransactionAttribute。接下来继续介绍另外一个分支:


DelegatingTransactionDefinition

一样的也就是个代理抽象类,啥都木有做。内部持有一个TransactionDefinition targetDefinition的引用而已,所有方法都是委托给targetDefinition去做的


ResourceTransactionDefinition

这个子接口非常的新,是Spring5.1才提供的


// @since 5.1
// 指示资源事务,尤其是事务性资源是否准备好进行本地优化
public interface ResourceTransactionDefinition extends TransactionDefinition {
  // 确定事务性资源是否准备好进行本地优化
  // @see #isReadOnly()
  boolean isLocalResource();
}



它和ResourceTransactionManager的使用相关联。ResourceTransactionManager是PlatformTransactionManager的一个子接口。

我们最常用的事务管理器DataSourceTransactionManager也实现了这个接口~~~~


目前Spring还未提供任何ResourceTransactionDefinition它的具体实现~


TransactionAttributeSource:事务属性源


它位于包:org.springframework.transaction.interceptor

它有点类似于之前讲过的TargetSource,它也是对TransactionAttribute进行了一层包装~~


public interface TransactionAttributeSource {
  // 通过Method和目标类,拿到事务属性~~~
  // 比如我们的@Transaction是标注在方法上的,可议自定义方法级别的事务属性,用它就特别的方便~
  @Nullable
  TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);
}


这里有很多人不明白了,为何都给了Method,为啥还要传入Class呢?难道Method还不知道它所属的类???

这里做如下解释:


  • method – 目前正在进行的方法调用
  • targetClass – 真正要调用的方法所在的类


这里是有细微差别的:


  • method的所属类不一样是targetClass。比如:method是代理对象的方法,它的所属类是代理出来的类
  • 但是:targetClass一定会有一个方法和method的方法签名一样

通常情况下,method的所属类会是targetClass的某个祖先类或者实现的某个接口。(动态代理)


它的实现有多种:

image.png


TransactionAttributeSource一般都是作为TransactionInterceptor的一个属性被set进去,然后看看这个事务属性可以作用在不同的方法上面,实现不同方法的个性化定制~

(实际真正处理它的是父类TransactionAspectSupport,它会做匹配~~~~) 具体的在详解TransactionInterceptor的时候会讲述到


NameMatchTransactionAttributeSource


根据名字就能匹配,然后该事务属性就会作用在对应的方法上。比如下面例子:


    // 自定义配置一个事务拦截器(@Transaction注解也会使用此拦截器进行拦截)
    @Bean
    public TransactionInterceptor transactionInterceptor(PlatformTransactionManager transactionManager) {
        Map<String, TransactionAttribute> txMap = new HashMap<>();
        // required事务  适用于觉得部分场景~
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
        requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(RuntimeException.class)));
        requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        txMap.put("add*", requiredTx);
        txMap.put("save*", requiredTx);
        txMap.put("insert*", requiredTx);
        txMap.put("update*", requiredTx);
        txMap.put("delete*", requiredTx);
        // 查询 使用只读事务
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED);
        txMap.put("get*", readOnlyTx);
        txMap.put("query*", readOnlyTx);
        // 定义事务属性的source~~~ 此处使用它  也就是根据方法名进行匹配的~~~
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        source.setNameMap(txMap);
        return new TransactionInterceptor(transactionManager, source);
    }


这个在我们基于XML的配置事务的时候,原理就是这样的~~


注意此处的匹配模式也是基于简单匹配的:PatternMatchUtils.simpleMatch。而非强大的正则匹配。底层getTransactionAttribute()时会根据不同的方法名,来返回不同的事务属性~~~


MethodMapTransactionAttributeSource


它的使用方式和NameMatchTransactionAttributeSource基本相同,但是有一个不同在于:


如果使用NameMatchTransactionAttributeSource配置属性源,比如get*配置为执行事务,那么所有的bean的get方法都会被加上事务,这可能不是我们想要的,因此对于自动代理,我们更好的选择是MethodMapTransactionAttributeSource,它需要指定需要事务化的完整类名和方法名


CompositeTransactionAttributeSource


若看前面AOP文章的详细讲解,讲述过它ComposablePointcut:

【小家Spring】Spring AOP各个组件概述与总结【Pointcut、Advice、Advisor、Advised、TargetSource、AdvisorChainFactory…】

它代表一种组合模式。


// @since 2.0 它是Spring2.0后才推出来的
public class CompositeTransactionAttributeSource implements TransactionAttributeSource, Serializable {
  private final TransactionAttributeSource[] transactionAttributeSources;
  public CompositeTransactionAttributeSource(TransactionAttributeSource... transactionAttributeSources) {
    Assert.notNull(transactionAttributeSources, "TransactionAttributeSource array must not be null");
    this.transactionAttributeSources = transactionAttributeSources;
  }
  // 这个实现方法也很容易。多个TransactionAttributeSource放在一起,只要任意一个匹配上就成
  // 备注:若匹配上多个,请注意先后顺序就成   这里面是数组  会保持和你放入的顺序一样~~~
  @Override
  @Nullable
  public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
    for (TransactionAttributeSource source : this.transactionAttributeSources) {
      TransactionAttribute attr = source.getTransactionAttribute(method, targetClass);
      if (attr != null) {
        return attr;
      }
    }
    return null;
  }
}
相关文章
|
29天前
|
Java Spring
【Spring】方法注解@Bean,配置类扫描路径
@Bean方法注解,如何在同一个类下面定义多个Bean对象,配置扫描路径
170 73
|
18天前
|
SQL Java 关系型数据库
【SpringFramework】Spring事务
本文简述Spring中数据库及事务相关衍伸知识点。
45 9
|
26天前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
85 13
|
29天前
|
Java Spring
【Spring配置相关】启动类为Current File,如何更改
问题场景:当我们切换类的界面的时候,重新启动的按钮是灰色的,不能使用,并且只有一个Current File 项目,下面介绍两种方法来解决这个问题。
|
1月前
|
缓存 安全 Java
Spring高手之路26——全方位掌握事务监听器
本文深入探讨了Spring事务监听器的设计与实现,包括通过TransactionSynchronization接口和@TransactionalEventListener注解实现事务监听器的方法,并通过实例详细展示了如何在事务生命周期的不同阶段执行自定义逻辑,提供了实际应用场景中的最佳实践。
55 2
Spring高手之路26——全方位掌握事务监听器
|
1月前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
2月前
|
Java 开发者 Spring
Spring高手之路24——事务类型及传播行为实战指南
本篇文章深入探讨了Spring中的事务管理,特别是事务传播行为(如REQUIRES_NEW和NESTED)的应用与区别。通过详实的示例和优化的时序图,全面解析如何在实际项目中使用这些高级事务控制技巧,以提升开发者的Spring事务管理能力。
66 1
Spring高手之路24——事务类型及传播行为实战指南
|
2月前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
|
2月前
|
XML Java 数据库连接
Spring中的事务是如何实现的
Spring中的事务管理机制通过一系列强大的功能和灵活的配置选项,为开发者提供了高效且可靠的事务处理手段。无论是通过注解还是AOP配置,Spring都能轻松实现复杂的事务管理需求。掌握这些工具和最佳实践,能
89 3
|
3月前
|
Java 关系型数据库 MySQL
Spring事务失效,我总结了这7个主要原因
本文详细探讨了Spring事务在日常开发中常见的七个失效原因,包括数据库不支持事务、类不受Spring管理、事务方法非public、异常被捕获、`rollbackFor`属性配置错误、方法内部调用事务方法及事务传播属性使用不当。通过具体示例和源码分析,帮助开发者更好地理解和应用Spring事务机制,避免线上事故。适合所有使用Spring进行业务开发的工程师参考。
53 2