【小家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;
  }
}
相关文章
|
3月前
|
Java Spring
Spring boot 运行服务jar外配置配置文件方式总结
Spring boot 运行服务jar外配置配置文件方式总结
491 0
|
2月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
3月前
|
Java 关系型数据库 MySQL
Spring 事务失效场景总结
Spring 事务失效场景总结
46 4
|
7天前
|
Java 数据库连接 数据库
spring复习05,spring整合mybatis,声明式事务
这篇文章详细介绍了如何在Spring框架中整合MyBatis以及如何配置声明式事务。主要内容包括:在Maven项目中添加依赖、创建实体类和Mapper接口、配置MyBatis核心配置文件和映射文件、配置数据源、创建sqlSessionFactory和sqlSessionTemplate、实现Mapper接口、配置声明式事务以及测试使用。此外,还解释了声明式事务的传播行为、隔离级别、只读提示和事务超时期间等概念。
spring复习05,spring整合mybatis,声明式事务
|
10天前
|
Java 测试技术 数据库
Spring事务传播机制(最全示例)
在使用Spring框架进行开发时,`service`层的方法通常带有事务。本文详细探讨了Spring事务在多个方法间的传播机制,主要包括7种传播类型:`REQUIRED`、`SUPPORTS`、`MANDATORY`、`REQUIRES_NEW`、`NOT_SUPPORTED`、`NEVER` 和 `NESTED`。通过示例代码和数据库插入测试,逐一展示了每种类型的运作方式。例如,`REQUIRED`表示如果当前存在事务则加入该事务,否则创建新事务;`SUPPORTS`表示如果当前存在事务则加入,否则以非事务方式执行;`MANDATORY`表示必须在现有事务中运行,否则抛出异常;
42 4
Spring事务传播机制(最全示例)
|
5天前
|
Java Spring
Spring 事务传播机制是什么?
Spring 事务传播机制是什么?
14 4
|
2月前
|
Java 程序员 数据库连接
女朋友不懂Spring事务原理,今天给她讲清楚了!
该文章讲述了如何解释Spring事务管理的基本原理,特别是针对女朋友在面试中遇到的问题。文章首先通过一个简单的例子引入了传统事务处理的方式,然后详细讨论了Spring事务管理的实现机制。
女朋友不懂Spring事务原理,今天给她讲清楚了!
|
2月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
23 0
Spring高手之路22——AOP切面类的封装与解析
|
2月前
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
2月前
|
前端开发 Java 数据库连接
一天十道Java面试题----第五天(spring的事务传播机制------>mybatis的优缺点)
这篇文章总结了Java面试中的十个问题,包括Spring事务传播机制、Spring事务失效条件、Bean自动装配方式、Spring、Spring MVC和Spring Boot的区别、Spring MVC的工作流程和主要组件、Spring Boot的自动配置原理和Starter概念、嵌入式服务器的使用原因,以及MyBatis的优缺点。
下一篇
无影云桌面