【小家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;
  }
}
相关文章
|
4月前
|
Java Spring
Spring中事务失效的场景
因为Spring事务是基于代理来实现的,所以某个加了@Transactional的⽅法只有是被代理对象调⽤时, 那么这个注解才会⽣效 , 如果使用的是被代理对象调用, 那么@Transactional会失效 同时如果某个⽅法是private的,那么@Transactional也会失效,因为底层cglib是基于⽗⼦类来实现 的,⼦类是不能重载⽗类的private⽅法的,所以⽆法很好的利⽤代理,也会导致@Transactianal失效 如果在业务中对异常进行了捕获处理 , 出现异常后Spring框架无法感知到异常, @Transactional也会失效
|
4月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——常见问题总结
本文总结了Spring Boot中使用事务的常见问题,虽然通过`@Transactional`注解可以轻松实现事务管理,但在实际项目中仍有许多潜在坑点。文章详细分析了三个典型问题:1) 异常未被捕获导致事务未回滚,需明确指定`rollbackFor`属性;2) 异常被try-catch“吃掉”,应避免在事务方法中直接处理异常;3) 事务范围与锁范围不一致引发并发问题,建议调整锁策略以覆盖事务范围。这些问题看似简单,但一旦发生,排查难度较大,因此开发时需格外留意。最后,文章提供了课程源代码下载地址,供读者实践参考。
81 0
|
4月前
|
Java 关系型数据库 数据库
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——Spring Boot 事务配置
本文介绍了 Spring Boot 中的事务配置与使用方法。首先需要导入 MySQL 依赖,Spring Boot 会自动注入 `DataSourceTransactionManager`,无需额外配置即可通过 `@Transactional` 注解实现事务管理。接着通过创建一个用户插入功能的示例,展示了如何在 Service 层手动抛出异常以测试事务回滚机制。测试结果表明,数据库中未新增记录,证明事务已成功回滚。此过程简单高效,适合日常开发需求。
195 0
|
4月前
|
Java 数据库 微服务
微服务——SpringBoot使用归纳——Spring Boot事务配置管理——事务相关
本文介绍Spring Boot事务配置管理,阐述事务在企业应用开发中的重要性。事务确保数据操作可靠,任一异常均可回滚至初始状态,如转账、购票等场景需全流程执行成功才算完成。同时,事务管理在Spring Boot的service层广泛应用,但根据实际需求也可能存在无需事务的情况,例如独立数据插入操作。
54 0
|
2月前
|
人工智能 Java 数据库连接
Spring事务失效场景
本文深入探讨了Spring框架中事务管理可能失效的几种常见场景及解决方案,包括事务方法访问级别不当、方法内部自调用、错误的异常处理、事务管理器或数据源配置错误、数据库不支持事务以及不合理的事务传播行为或隔离级别。通过合理配置和正确使用`@Transactional`注解,开发者可以有效避免这些问题,确保应用的数据一致性和完整性。
113 10
|
1月前
|
Java 关系型数据库 MySQL
【Spring】【事务】初学者直呼学会了的Spring事务入门
本文深入解析了Spring事务的核心概念与使用方法。Spring事务是一种数据库事务管理机制,通过确保操作的原子性、一致性、隔离性和持久性(ACID),维护数据完整性。文章详细讲解了声明式事务(@Transactional注解)和编程式事务(TransactionTemplate、PlatformTransactionManager)的区别与用法,并探讨了事务传播行为(如REQUIRED、REQUIRES_NEW等)及隔离级别(如READ_COMMITTED、REPEATABLE_READ)。
109 1
|
4月前
|
SQL Java 数据库连接
Spring中的事务是如何实现的
1. Spring事务底层是基于数据库事务和AOP机制的 2. ⾸先对于使⽤了@Transactional注解的Bean,Spring会创建⼀个代理对象作为Bean 3. 当调⽤代理对象的⽅法时,会先判断该⽅法上是否加了@Transactional注解 4. 如果加了,那么则利⽤事务管理器创建⼀个数据库连接 5. 并且修改数据库连接的autocommit属性为false,禁⽌此连接的⾃动提交,这是实现Spring事务⾮ 常重要的⼀步 6. 然后执⾏当前⽅法,⽅法中会执⾏sql 7. 执⾏完当前⽅法后,如果没有出现异常就直接提交事务 8. 如果出现了异常,并且这个异常是需要回滚的就会回滚事务
|
4月前
|
JavaScript Java 开发者
Spring事务失效,常见的情况有哪些?
本文总结了Spring事务失效的7种常见情况,包括未启用事务管理功能、方法非public类型、数据源未配置事务管理器、自身调用问题、异常类型错误、异常被吞以及业务和事务代码不在同一线程中。同时提供了两种快速定位事务相关Bug的方法:通过查看日志(设置为debug模式)或调试代码(在TransactionInterceptor的invoke方法中设置断点)。文章帮助开发者更好地理解和解决Spring事务中的问题。
114 7
|
3月前
|
前端开发 IDE Java
Spring MVC 中因导入错误的 Model 类报错问题解析
在 Spring MVC 或 Spring Boot 开发中,若导入错误的 `Model` 类(如 `ch.qos.logback.core.model.Model`),会导致无法解析 `addAttribute` 方法的错误。正确类应为 `org.springframework.ui.Model`。此问题通常因 IDE 自动导入错误类引起。解决方法包括:删除错误导入、添加正确包路径、验证依赖及清理缓存。确保代码中正确使用 Spring 提供的 `Model` 接口以实现前后端数据传递。
116 0
|
6月前
|
SQL Java 关系型数据库
【SpringFramework】Spring事务
本文简述Spring中数据库及事务相关衍伸知识点。
77 9

热门文章

最新文章