Spring底层事务原理

简介: Spring底层事务原理

Spring底层事务原理


Spring事务底层原理

一、@EnableTransactionManagement工作原理

二、Spring事务基本执行原理

三、Spring事务的过程

四、Spring事务传播机制

五、Spring事务传播机制分类

(1)案例分析、情况1

(2)案例分析、情况2

(3)案例分析、情况3

(4)案例分析、情况4

六、Spring事务强制回滚

七、TransactionSynchronization

一、@EnableTransactionManagement工作原理

开启Spring事务本质上就是增加了一个Advisor,但我们使用 @EnableTransactionManagement注解来开启Spring事务是,该注解代理的功能就是向Spring容器中添加了两个Bean:

(1)AutoProxyRegistrar
(2)ProxyTransactionManagementConfiguration

(1)AutoProxyRegistrar

主要的作用是向Spring容器中注册了一个InfrastructureAdvisorAutoProxyCreator的Bean。

而InfrastructureAdvisorAutoProxyCreator继承了AbstractAdvisorAutoProxyCreator,所以这个类的主要作用就是开启自动代理的作用,也就是一个BeanPostProcessor,会在初始化后步骤中去寻找Advisor类型的Bean,并判断当前某个Bean是否有匹配的Advisor,是否需要利用动态代理产生一个代理对象。

(2)ProxyTransactionManagementConfiguration是一个配置类,它又定义了另外三个bean:

image.png

二、Spring事务基本执行原理

一个Bean在执行Bean的创建生命周期时,会经过InfrastructureAdvisorAutoProxyCreator的初始化后的方法,会判断当前Bean对象是否BeanFactoryTransactionAttributeSourceAdvisor匹配,匹配逻辑为判断该Bean的类上是否存在@Transactional注解,或者类中的某个方法上是否存在@Transactional注解,如果存在则表示该Bean需要进行动态代理产生一个代理对象作为Bean对象。

该代理对象在执行某个方法时,会再次判断当前执行的方法是否和BeanFactoryTransactionAttributeSourceAdvisor匹配,如果匹配则执行该Advisor中的TransactionInterceptor的invoke()方法,

执行基本流程为:

利用所配置的PlatformTransactionManager事务管理器新建一个数据库连接

修改数据库连接的autocommit为false

执行MethodInvocation.proceed()方法,简单理解就是执行业务方法,其中就会执行sql

如果没有抛异常,则提交

如果抛了异常,则回滚

三、Spring事务的过程

1、数据库:建立连接、开启事务、进行sql操作、成功提交、失败回滚

2、业务逻辑:准备工作(可以进行前置通知)、开启事务、事务操作、成功提交(可以后置通知)、失败回滚(异常通知)

spring的事务是由aop实现的,首先要生成具体的代理对象,然后按照aop流程执行具体

的操作逻辑,正常情况下要通过通知来完成核心功能,但是事务部署通过通知来实现的,

而是通过TransactionInterceptor来实现的,然后调用invoke来实现具体的逻辑。

步骤如下:

1、先做准备工作,解析各个方法上事务相关的属性,根据具体的属性来判断是否开始新事务。

2、当需要开启的时候获取数据库连接,关闭自动提交功能,开启事务。

3、执行具体的sql逻辑操作,在操作的过程中如果执行失败会通过 completeTransactionafterthrowing来完成事务的回滚操作,回滚的

具体逻辑是通过dorollback方法实现,实现时也要先获取连接对象,

然后通过连接对象进行回滚(conn.rollback)。

4、如果执行成功,那么通过completeTransactionafterrunning来完成事务的提交操作,

具体逻辑是通过docommit方法来实现,实现的时候也是先获取连接,通过连接对象来

进行提交(conn.commit)。

5、最后事务执行完毕需要清除事务相关的事务信息(cleanupTransactioninfo)。

四、Spring事务传播机制

在开发过程中,经常会出现一个方法调用另外一个方法,那么这里就涉及到了多种场景,比如a()调用b():

a()和b()方法中的所有sql需要在同一个事务中吗?

a()和b()方法中的所有sql需要在同一个事务中吗?

a()需要在事务中执行,b()还需要在事务中执行吗?

或者其他情况

这种情况下就要求Spring事务能支持上面各种场景,这就是Spring事务传播机制的由来。

那Spring事务传播机制是如何实现的呢?

先描述其中一个场景中情况,a()在一个事务中执行,调用b()方法时需要新开一个事务执行:

代理对象执行a()方法前,先利用事务管理器新建一个数据库连接a

将数据库连接a的autocommit改为false

把数据库连接a设置到ThreadLocal中

执行a()方法中的sql

执行a()方法过程中,调用了b()方法(注意用代理对象调用b()方法)

a()方法正常执行完,则从ThreadLocal中拿到数据库连接a进行提交

关于步骤5的一些详细解释:

1、代理对象执行b()方法前,判断出来了当前线程中已经存在一个数据库连接a了,表示当前线程其实已经拥有一个Spring事务了,则进行挂起

2、挂起就是把ThreadLocal中的数据库连接a从ThreadLocal中移除,并放入一个挂起资源对象中

3、挂起完成后,再次利用事务管理器新建一个数据库连接b

4、将数据库连接b的autocommit改为false

5、把数据库连接b设置到ThreadLocal中

6、执行b()方法中的sql

7、b()方法正常执行完,则从ThreadLocal中拿到数据库连接b进行提交

8、提交之后会恢复所挂起的数据库连接a,这里的恢复,其实只是把在挂起资源对象中所保存的数据库连接a再次设置到ThreadLocal中

过程中最为重要的是:在执行某个方法时,判断当前是否已经存在一个事务,就是判断当前线程的ThreadLocal中是否存在一个数据库连接对象,如果存在则表示已经存在一个事务了。

五、Spring事务传播机制分类

在这里面,以非事务方式运行,表示以非Spring事务运行,表示在执行这个方法时,Spring事务管理器不会去建立数据库连接,执行sql时,由Mybatis或JdbcTemplate自己来建立数据库连接来执行sql。

(1)案例分析、情况1

默认情况下传播机制为REQUIRED,表示当前如果没有事务则新建一个事务,如果有事务则在当前事务中执行。

@Component
public class UserService {
  @Autowired
  private UserService userService;
  @Transactional
  public void test() {
      // test方法中的sql
      userService.a();
  }
  @Transactional
  public void a() {
      // a方法中的sql
  }
}

所以情况1的执行流程如下:

1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、执行a方法中的sql
5、执行conn的commit()方法进行提交

(2)案例分析、情况2

如果是这种情况:

@Component
public class UserService {
  @Autowired
  private UserService userService;
  @Transactional
  public void test() {
      // test方法中的sql
      userService.a();
        int result = 100/0;
  }
  @Transactional
  public void a() {
      // a方法中的sql
  }
}

所以情况2的执行流程如下:

1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、执行a方法中的sql
5、抛出异常
6、执行conn的rollback()方法进行回滚,所以两个方法中的sql都会回滚掉

(3)案例分析、情况3

@Component
public class UserService {
  @Autowired
  private UserService userService;
  @Transactional
  public void test() {
      // test方法中的sql
      userService.a();
  }
  @Transactional
  public void a() {
      // a方法中的sql
        int result = 100/0;
  }
}

所以情况3的执行流程如下:

1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、执行a方法中的sql
5、抛出异常
6、执行conn的rollback()方法进行回滚,所以两个方法中的sql都会回滚掉

(4)案例分析、情况4

@Component
public class UserService {
  @Autowired
  private UserService userService;
  @Transactional
  public void test() {
      // test方法中的sql
    userService.a();
  }
  @Transactional(propagation = Propagation.REQUIRES_NEW)
  public void a() {
      // a方法中的sql
      int result = 100/0;
  }
}

所以情况3的执行流程如下:

1、新建一个数据库连接conn
2、设置conn的autocommit为false
3、执行test方法中的sql
4、又新建一个数据库连接conn2
5、执行a方法中的sql
6、抛出异常
7、执行conn2的rollback()方法进行回滚
8、继续抛异常,对于test()方法而言,它会接收到一个异常,然后抛出
9、执行conn的rollback()方法进行回滚,最终还是两个方法中的sql都回滚了

六、Spring事务强制回滚

正常情况下,a()调用b()方法时,如果b()方法抛了异常,但是a()方法捕获了,那么a()的事务还是会正常提交的,但是有的时候,我们捕获异常可能只是不把异常信息返回给客户端,而是为了返回一些更优良的错误信息,所以在这个时候,我们还是希望事务能回滚的,那就得告诉Spring把当前事务回滚掉,做法就是:

@Transactional
public void test(){
    // 执行sql
  try {
      b();
  } catch (Exception e) {
    // 构造友好的错误信息返回
    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  }
}
public void b() throws Exception {
  throw new Exception();
}

七、TransactionSynchronization

Spring事务有可能会提交,回滚、挂起、恢复,所以Spring事务提供了一种机制,可以让程序员来监听当前Spring事务所处于的状态。

@Component
public class UserService {
 @Autowired
 private JdbcTemplate jdbcTemplate;
 @Autowired
 private UserService userService;
 @Transactional
 public void test(){
  TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
   @Override
   public void suspend() {
    System.out.println("test被挂起");
   }
   @Override
   public void resume() {
    System.out.println("test被恢复");
   }
   @Override
   public void beforeCommit(boolean readOnly) {
    System.out.println("test准备要提交");
   }
   @Override
   public void beforeCompletion() {
    System.out.println("test准备要提交或回滚");
   }
   @Override
   public void afterCommit() {
    System.out.println("test提交成功");
   }
   @Override
   public void afterCompletion(int status) {
    System.out.println("test提交或回滚成功");
   }
  });
  jdbcTemplate.execute("insert into t1 values(1,1,1,1,'1')");
  System.out.println("test");
  userService.a();
 }
 @Transactional(propagation = Propagation.REQUIRES_NEW)
 public void a(){
  TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
   @Override
   public void suspend() {
    System.out.println("a被挂起");
   }
   @Override
   public void resume() {
    System.out.println("a被恢复");
   }
   @Override
   public void beforeCommit(boolean readOnly) {
    System.out.println("a准备提交");
   }
   @Override
   public void beforeCompletion() {
    System.out.println("a准备提交或回滚");
   }
   @Override
   public void afterCommit() {
    System.out.println("a提交成功");
   }
   @Override
   public void afterCompletion(int status) {
    System.out.println("a提交或回滚成功");
   }
  });
  jdbcTemplate.execute("insert into t1 values(2,2,2,2,'2')");
  System.out.println("a");
 }
}
相关文章
|
5天前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
3天前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
22天前
|
Java 关系型数据库 MySQL
Spring 事务失效场景总结
Spring 事务失效场景总结
39 4
|
1月前
|
Java 应用服务中间件 开发者
Java面试题:解释Spring Boot的优势及其自动配置原理
Java面试题:解释Spring Boot的优势及其自动配置原理
87 0
|
1月前
|
设计模式 监控 Java
解析Spring Cloud中的断路器模式原理
解析Spring Cloud中的断路器模式原理
|
3天前
|
XML Java 数据格式
Spring5入门到实战------2、IOC容器底层原理
这篇文章深入探讨了Spring5框架中的IOC容器,包括IOC的概念、底层原理、以及BeanFactory接口和ApplicationContext接口的介绍。文章通过图解和实例代码,解释了IOC如何通过工厂模式和反射机制实现对象的创建和管理,以及如何降低代码耦合度,提高开发效率。
Spring5入门到实战------2、IOC容器底层原理
|
6天前
|
Java 程序员 数据库连接
女朋友不懂Spring事务原理,今天给她讲清楚了!
该文章讲述了如何解释Spring事务管理的基本原理,特别是针对女朋友在面试中遇到的问题。文章首先通过一个简单的例子引入了传统事务处理的方式,然后详细讨论了Spring事务管理的实现机制。
女朋友不懂Spring事务原理,今天给她讲清楚了!
|
3天前
|
XML Java 数据库
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
这篇文章是Spring5框架的实战教程,详细介绍了事务的概念、ACID特性、事务操作的场景,并通过实际的银行转账示例,演示了Spring框架中声明式事务管理的实现,包括使用注解和XML配置两种方式,以及如何配置事务参数来控制事务的行为。
Spring5入门到实战------15、事务操作---概念--场景---声明式事务管理---事务参数--注解方式---xml方式
|
3天前
|
XML Java 数据格式
Spring5入门到实战------2、IOC容器底层原理
这篇文章深入探讨了Spring5框架中的IOC容器,包括IOC的概念、底层原理、以及BeanFactory接口和ApplicationContext接口的介绍。文章通过图解和实例代码,解释了IOC如何通过工厂模式和反射机制实现对象的创建和管理,以及如何降低代码耦合度,提高开发效率。
Spring5入门到实战------2、IOC容器底层原理
|
5天前
|
前端开发 Java 数据库连接
一天十道Java面试题----第五天(spring的事务传播机制------>mybatis的优缺点)
这篇文章总结了Java面试中的十个问题,包括Spring事务传播机制、Spring事务失效条件、Bean自动装配方式、Spring、Spring MVC和Spring Boot的区别、Spring MVC的工作流程和主要组件、Spring Boot的自动配置原理和Starter概念、嵌入式服务器的使用原因,以及MyBatis的优缺点。