Spring事务处理原理步骤详解

1、事务处理实现

实现步骤:

* 声明式事务:
*
* 环境搭建:
* 1、导入相关依赖
* 数据源、数据库驱动、Spring-jdbc模块
* 2、配置数据源、JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据
* 3、给方法上标注 @Transactional 表示当前方法是一个事务方法;
* 4、 @EnableTransactionManagement 开启基于注解的事务管理功能;
* @EnableXXX
* 5、配置事务管理器来控制事务;
* @Bean
* public PlatformTransactionManager transactionManager()

代码实现:

@EnableTransactionManagement
@ComponentScan("com.atguigu.tx")
@Configuration
public class TxConfig {

  //数据源
  @Bean
  public DataSource dataSource() throws Exception{
    ComboPooledDataSource dataSource = new ComboPooledDataSource();
    dataSource.setUser("root");
    dataSource.setPassword("123456");
    dataSource.setDriverClass("com.mysql.jdbc.Driver");
    dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
    return dataSource;
  }

  @Bean
  public JdbcTemplate jdbcTemplate() throws Exception{
    //Spring对@Configuration类会特殊处理;给容器中加组件的方法,多次调用都只是从容器中找组件
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
    return jdbcTemplate;
  }

  //注册事务管理器在容器中
  @Bean
  public PlatformTransactionManager transactionManager() throws Exception{
    return new DataSourceTransactionManager(dataSource());
  }
} 

2、事务处理原理

原理分析:

* 原理:
* 1)、@EnableTransactionManagement
* 利用TransactionManagementConfigurationSelector给容器中会导入组件
* 导入两个组件
* AutoProxyRegistrar
* ProxyTransactionManagementConfiguration
* 2)、AutoProxyRegistrar:
* 给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;
* InfrastructureAdvisorAutoProxyCreator:?
* 利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;
*
* 3)、ProxyTransactionManagementConfiguration 做了什么?
* 1、给容器中注册事务增强器;
* 1)、事务增强器要用事务注解的信息,AnnotationTransactionAttributeSource解析事务注解
* 2)、事务拦截器:
* TransactionInterceptor;保存了事务属性信息,事务管理器;
* 他是一个 MethodInterceptor;
* 在目标方法执行的时候;
* 执行拦截器链;
* 事务拦截器:
* 1)、先获取事务相关的属性
* 2)、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger
* 最终会从容器中按照类型获取一个PlatformTransactionManager;
* 3)、执行目标方法
* 如果异常,获取到事务管理器,利用事务管理回滚操作;
* 如果正常,利用事务管理器,提交事务
*
*/

核心代码

1、EnableTransactionManagement注解,注入TransactionManagementConfigurationSelector类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {

2、TransactionManagementConfigurationSelector类,最终会导入AutoProxyRegistrar.class和ProxyTransactionManagementConfiguration.class两个组件。

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {

  /**
   * Returns {@link ProxyTransactionManagementConfiguration} or
   * {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
   * and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
   * respectively.
   */
  @Override
  protected String[] selectImports(AdviceMode adviceMode) {
    switch (adviceMode) {
      case PROXY:
        return new String[] {AutoProxyRegistrar.class.getName(),
            ProxyTransactionManagementConfiguration.class.getName()};
      case ASPECTJ:
        return new String[] {determineTransactionAspectClass()};
      default:
        return null;
    }
  }

  private String determineTransactionAspectClass() {
    return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ?
        TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
        TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
  }

}

3、AutoProxyRegistrar类的作用为:

  给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 组件;

  最终的目的是:利用后置处理器机制在对象创建以后,包装对象,返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;

@Override
  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    boolean candidateFound = false;
    Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
    for (String annType : annTypes) {
      AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
      if (candidate == null) {
        continue;
      }
      Object mode = candidate.get("mode");
      Object proxyTargetClass = candidate.get("proxyTargetClass");
      if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
          Boolean.class == proxyTargetClass.getClass()) {
        candidateFound = true;
        if (mode == AdviceMode.PROXY) {
          AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
          if ((Boolean) proxyTargetClass) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
            return;
          }
        }
      }
    }
    if (!candidateFound && logger.isInfoEnabled()) {
      String name = getClass().getSimpleName();
      logger.info(String.format("%s was imported but no annotations were found " +
          "having both 'mode' and 'proxyTargetClass' attributes of type " +
          "AdviceMode and boolean respectively. This means that auto proxy " +
          "creator registration and configuration may not have occurred as " +
          "intended, and components may not be proxied as expected. Check to " +
          "ensure that %s has been @Import'ed on the same class where these " +
          "annotations are declared; otherwise remove the import of %s " +
          "altogether.", name, name, name));
    }
  }

InfrastructureAdvisorAutoProxyCreator类的作用与AnnotationAwareAspectJAutoProxyCreator类的作用类似。

@SuppressWarnings("serial")
public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport
    implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {

4、ProxyTransactionManagementConfiguration类

代理事务管理配置类

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

  @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
    BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
    advisor.setTransactionAttributeSource(transactionAttributeSource());
    advisor.setAdvice(transactionInterceptor());
    if (this.enableTx != null) {
      advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
    }
    return advisor;
  }

  @Bean
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public TransactionAttributeSource transactionAttributeSource() {
    return new AnnotationTransactionAttributeSource();
  }

  @Bean
  @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  public TransactionInterceptor transactionInterceptor() {
    TransactionInterceptor interceptor = new TransactionInterceptor();
    interceptor.setTransactionAttributeSource(transactionAttributeSource());
    if (this.txManager != null) {
      interceptor.setTransactionManager(this.txManager);
    }
    return interceptor;
  }

}

TransactionInterceptor类,事务调用:invokeWithinTransaction()方法为最终执行的方法

@Override
  @Nullable
  public Object invoke(MethodInvocation invocation) throws Throwable {
    // Work out the target class: may be {@code null}.
    // The TransactionAttributeSource should be passed the target class
    // as well as the method, which may be from an interface.
    Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

    // Adapt to TransactionAspectSupport's invokeWithinTransaction...
    return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
  }

TransactionAspectSupport类的最终事务方法执行:

@Nullable
  protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      final InvocationCallback invocation) throws Throwable {

    // If the transaction attribute is null, the method is non-transactional.
    TransactionAttributeSource tas = getTransactionAttributeSource();
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    final PlatformTransactionManager tm = determineTransactionManager(txAttr);
    final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

    if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
      // Standard transaction demarcation with getTransaction and commit/rollback calls.
      TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

      Object retVal;
      try {
        // This is an around advice: Invoke the next interceptor in the chain.
        // This will normally result in a target object being invoked.
        retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
        // target invocation exception
        completeTransactionAfterThrowing(txInfo, ex);
        throw ex;
      }
      finally {
        cleanupTransactionInfo(txInfo);
      }
      commitTransactionAfterReturning(txInfo);
      return retVal;
    }

    else {
      final ThrowableHolder throwableHolder = new ThrowableHolder();

      // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
      try {
        Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
          TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
          try {
            return invocation.proceedWithInvocation();
          }
          catch (Throwable ex) {
            if (txAttr.rollbackOn(ex)) {
              // A RuntimeException: will lead to a rollback.
              if (ex instanceof RuntimeException) {
                throw (RuntimeException) ex;
              }
              else {
                throw new ThrowableHolderException(ex);
              }
            }
            else {
              // A normal return value: will lead to a commit.
              throwableHolder.throwable = ex;
              return null;
            }
          }
          finally {
            cleanupTransactionInfo(txInfo);
          }
        });

        // Check result state: It might indicate a Throwable to rethrow.
        if (throwableHolder.throwable != null) {
          throw throwableHolder.throwable;
        }
        return result;
      }
      catch (ThrowableHolderException ex) {
        throw ex.getCause();
      }
      catch (TransactionSystemException ex2) {
        if (throwableHolder.throwable != null) {
          logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
          ex2.initApplicationException(throwableHolder.throwable);
        }
        throw ex2;
      }
      catch (Throwable ex2) {
        if (throwableHolder.throwable != null) {
          logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
        }
        throw ex2;
      }
    }
  }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Spring声明式事务@Transactional知识点分享

    @Transactional注解支持9个属性的设置,这里只讲解其中使用较多的三个属性:readOnly.propagation.isolation.其中propagation属性用来枚举事务的传播行为,isolation用来设置事务隔离级别,readOnly进行读写事务控制. @Service @Transactional(readOnly = true) public class AppTradeRec2Service extends BaseService { @Autowired priv

  • Spring如何在一个事务中开启另一个事务

    这篇文章主要介绍了Spring如何在一个事务中开启另一个事务,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 spring使用@Transactional开启事务,而且该注解使用propagation属性来指定事务的传播级别 @Transactional(propagation =Propagation.REQUIRES_NEW) // 开启一个新事务 使用REQUIRES_NEW就会开启一个新的事务吗? 答案并不是. 请看下面的这个示例 imp

  • Spring如何基于aop实现事务控制

    spring的事务控制本质上是通过aop实现的. 在springboot中使用时,可以通过注解@Transactional进行类或者方法级别的事务控制,也可以自己通过spring提供的事务管理器手动控制事务 一. @Transactional注解进行进行类或者方法级别的事务控制 不需要进行特别的设置,按照正常的配置整合spring和mybatis后,在需要进行事务控制的类上或者方法上加上 @Transactional注解,即可对其进行事务控制. 二.手动控制事务 当需要在一个方法的内部进行事务控

  • Spring事务相关问题解决方案

    有些spring相关的知识点之前一直没有仔细研究:比如spring的事务,并不是没有使用,也曾经简单的在某些需要事务处理的方法上通过增加事务注解来实现事务功能,仅仅是跟随使用(甚至并未测试过事务的正确性),至于如何在项目中配置事务,如何才能将事务写正确,事务的其它的一些原理性的东西从未花时间研究.最近同事正好抛出了一个问题,借此机会学习了一遍. 问题一:增加了readOnly=true的事务中包含写操作,为什么线上运行这段代码是正常的呢? @Transactional(readOnly = tr

  • Springboot通过aop实现事务控制过程解析

    spring的事务控制本质上是通过aop实现的. 在springboot中使用时,可以通过注解@Transactional进行类或者方法级别的事务控制,也可以自己通过spring提供的事务管理器手动控制事务 一. @Transactional注解进行进行类或者方法级别的事务控制 不需要进行特别的设置,按照正常的配置整合spring和mybatis后,在需要进行事务控制的类上或者方法上加上 @Transactional注解,即可对其进行事务控制. 二.手动控制事务 当需要在一个方法的内部进行事务控

  • SpringBoot内部调用事务不起作用问题的解决方案

    在做业务开发时,遇到了一个事务不起作用的问题.大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚.查阅资料后,问题得到解决,记录下来分享给大家. 场景 我在这里模拟一个场景,大概的调用方式就如下面的代码这样. @Override @Transactional(rollbackFor = RuntimeException.class) public void insertUser(User user) { userMapper.insertUser(user); thr

  • spring 声明式事务实现过程解析

    这篇文章主要介绍了spring 声明式事务实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 /** * 声明式事务: * * 环境搭建: * 1.导入相关依赖 * 数数据 * 3.给方法上标注 @Transactional 表示当前方法是一个事务方法: * 4. @EnableTransactionManagement 开启基于注解的事务管理功能:据源.数据库驱动.Spring-jdbc模块 * * 2.配置数据源.JdbcTempl

  • Spring事务处理原理步骤详解

    1.事务处理实现 实现步骤: * 声明式事务: * * 环境搭建: * 1.导入相关依赖 * 数据源.数据库驱动.Spring-jdbc模块 * 2.配置数据源.JdbcTemplate(Spring提供的简化数据库操作的工具)操作数据 * 3.给方法上标注 @Transactional 表示当前方法是一个事务方法: * 4. @EnableTransactionManagement 开启基于注解的事务管理功能: * @EnableXXX * 5.配置事务管理器来控制事务; * @Bean *

  • eclipse安装spring ide的步骤详解

    Eclipse配置springIDE插件的方法步骤 一.spring ide下载技巧 查看eclipse的版本号.(如我的就是4.17.0)(查看版本号方法:help=>about idea) 找到官网:https://github.com/spring-projects/toolsuite-distribution/wiki/Spring-Tool-Suite-3 找到自己版本所对应的红色标记. 根据官网下载规则可得出一下结论,下载地址拼接的方法. http://download.spring

  • 在Spring Boot应用程序中使用Apache Kafka的方法步骤详解

    第1步:生成我们的项目: Spring Initializr来生成我们的项目.我们的项目将提供Spring MVC / Web支持和Apache Kafka支持. 第2步:发布/读取Kafka主题中的消息: <b>public</b> <b>class</b> User { <b>private</b> String name; <b>private</b> <b>int</b> age

  • Java Spring之@Async原理案例详解

    目录 前言 一.如何使用@Async 二.源码解读 总结 前言 用过Spring的人多多少少也都用过@Async注解,至于作用嘛,看注解名,大概能猜出来,就是在方法执行的时候进行异步执行. 一.如何使用@Async 使用@Async注解主要分两步: 1.在配置类上添加@EnableAsync注解 @ComponentScan(value = "com.wang") @Configuration @EnableAsync public class AppConfig { } 2.在想要异

  • Spring Boot整合EhCache的步骤详解

    本文讲解Spring Boot与EhCache的整合. 1 EhCache简介 EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认CacheProvider.Ehcache是一种广泛使用的开源Java分布式缓存.主要面向通用缓存,Java EE和轻量级容器.它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点. 2 Spring Boot整合EhCache步骤 2.

  • Spring Cloud中使用jib进行docker部署的步骤详解

    Jib介绍 Jib 是 Google 开发的可以直接构建 Java 应用的 Docker 和 OCI 镜像的类库,以 Maven 和 Gradle 插件形式提供. 通过 Jib,Java 开发者可以使用他们熟悉的 Java 工具来构建容器.Jib 是一个快速而简单的容器镜像构建工具,它负责处理将应用程序打包到容器镜像中所需的所有步骤.它不需要你编写 Dockerfile 或安装 Docker,而且可以直接集成到 Maven 和 Gradle中 -- 只需要将插件添加到构建中,就可以立即将 Jav

  • Spring引入外部属性文件配置数据库连接的步骤详解

    直接配置数据库的信息 xml配置文件直接配置: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.sprin

  • Springboot集成Spring Security实现JWT认证的步骤详解

    1 简介 Spring Security作为成熟且强大的安全框架,得到许多大厂的青睐.而作为前后端分离的SSO方案,JWT也在许多项目中应用.本文将介绍如何通过Spring Security实现JWT认证. 用户与服务器交互大概如下: 客户端获取JWT,一般通过POST方法把用户名/密码传给server: 服务端接收到客户端的请求后,会检验用户名/密码是否正确,如果正确则生成JWT并返回:不正确则返回错误: 客户端拿到JWT后,在有效期内都可以通过JWT来访问资源了,一般把JWT放在请求头:一次

  • Spring Cloud Eureka 注册与发现操作步骤详解

    在搭建Spring Cloud Eureka环境前先要了解整个架构的组成,常用的基础模式如下图: 服务提供者:将springboot服务编写好以后,通过配置注册中心地址方式注册,提供给消费者使用. 注册中心:服务的中间桥梁,服务提供者将服务注册.服务消费者可以通过注册信息调用需要使用的服务. 服务消费者:通过规定的调用方式,读取注册中心的注册信息,调用相应的服务. 根据后续的服务复杂度进化以后,可以看到服务提供者也可以是服务消费者,服务消费者也可以是服务提供者.根据不同的业务情况是可以互相调用的

  • SpringBoot整合Swagger2的步骤详解

    简介 swagger是一个流行的API开发框架,这个框架以"开放API声明"(OpenAPI Specification,OAS)为基础, 对整个API的开发周期都提供了相应的解决方案,是一个非常庞大的项目(包括设计.编码和测试,几乎支持所有语言). springfox大致原理: springfox的大致原理就是,在项目启动的过种中,spring上下文在初始化的过程, 框架自动跟据配置加载一些swagger相关的bean到当前的上下文中,并自动扫描系统中可能需要生成api文档那些类,

随机推荐