女朋友不懂Spring事务原理,今天终于给她讲清楚了

女朋友最近在找新工作,被面试官频繁问Spring事务原理,女朋友没有看过Spring源码,一直要我给她讲原理,看到女朋友十分低落的表情,我下定决心一定要给他讲清楚了。
在这里插入图片描述

传统事务的做法

我一开始问她知不知道假如没有Spring要怎么实现事务,她说知道,我就要他把传统事务的流程图画出来给我看下,下面就是她给出的流程图:
在这里插入图片描述

传统事务存在哪些问题

果然计算机科班出身的女朋友,技术底子还是阔以的[你强],我再问她这种传统处理事务的方案有哪些局限或者短板呢? 她说,除了CRUD的业务代码,还需要写事务管理相关的代码,平时的工作量就加大了,这个确实如此,传统的事务做法对程序员的工作量大大提高,同时也补充了我的看法:

  1. 传统事务代码与业务代码耦合,强度入侵业务代码,可扩展性差
  2. 如果一个业务功能里同时存在多个事务切换的时候,代码编写的就会非常复杂

正是为了解决这些缺陷,Spring团队就打造了Spring事务组件,这个模块组件封装了传统事务功能的逻辑,业务开发者不用关心事务管理代码,只管专注于业务开发,多么美哉!
在这里插入图片描述

Spring事务组件做了哪些伟大的事?

1、Spring定义了事务操作规范,提供了顶层统一的编程模型抽象,不管是Java事务API,还是Hibernate,下面就是Spring定义的顶层接口,规范了对事务操作定义:

public interface PlatformTransactionManager {
    //获取事务
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
    //提交事务
    void commit(TransactionStatus var1) throws TransactionException;
    //回滚事务
    void rollback(TransactionStatus var1) throws TransactionException;
}

2、同时支持声明式事务和编程式事务 女朋友又开始问了,什么是编程式事务?什么是声明式事务呢? 编程式事务和传统事务类似,它是和业务代码耦合在一起的,只不过Spring团队对事务管理进行了封装,提供了工具类

org.springframework.transaction.support.TransactionTemplate

使用姿势如下面所示:

transactionTemplate.execute(() -> {
    //业务代码
    userService.addUser(user);
    scoreService.addScore(score);
});

那什么是声明式事务呢? 声明式事务就是通过注解的形式完成事务功能,如下面的代码可以等同于上面编程式事务,使我们的业务代码在事务中执行。

@Transactional
public void doTransaction() {
    userService.addUser(user);
    scoreService.addScore(score);
}
Spring事务实现原理剖析

女朋友开始感兴趣了,这些Spring是如何做到的呢?
在这里插入图片描述
首先说编程式事务,这个比较简单,扒开他的源码可知,他就是通过将业务代码以函数表达式传入一个工具方法,方法里在执行业务代码前后织入事务管理的逻辑,如下面代码:

public class TransactionTemplate {

public <T> T execute(TransactionCallback<T> action) throws TransactionException {
        	//获取数据库连接
            TransactionStatus status = transactionManager.getTransaction(this);
            Object result;
            try {
                //执行crud
                result = action.doInTransaction(status);
            } catch (Error | RuntimeException var5) {
                //异常回滚
                this.rollbackOnException(status, var5);
                throw var5;
            } catch (Throwable var6) {
                //异常回滚
                this.rollbackOnException(status, var6);
                throw new UndeclaredThrowableException(var6, "TransactionCallback threw undeclared checked exception");
            }
            //执行crud成功,提交事务
            this.transactionManager.commit(status);
            return result;
        }
    }
}

看到这个实现,就非常清楚了,Spring将事务管理代码和函数式编程结合完成了编程式事务的组装。

下面我重点讲下声明式事务的实现逻辑:
在这里插入图片描述
虽然表面上看着Spring通过一个注解就完成了事务的功能,实际上底层有很多的逻辑,它需要能够拦截事务方法,并且在事务方法前后嵌入事务管理逻辑,完成事务开启,提交,回滚等逻辑,在Spring生态中,AOP技术就是一种在方法前后嵌入一些通用代码的手段,确实如此,Spring声明式事务就是借助Spring的AOP能力实现的。

TransactionInterceptor就是Spring内部定义的一个切面,她实现了MethodInterceptor接口就像我们平时定义一个切面统一打印日志一样,这个切面是Spring内置的一个切面,专门用来处理数据库事务的。

在ProxyTransactionManagementConfiguration配置类中,对事务切面进行了定义:

//定义拦截器
@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;
}
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
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;
}

这样Spring容器启动之后,就有一个全局的事务切面了。拦截到@Transaction注解的方法时,会触发下面方法执行

public class TransactionInterceptor{
    @Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
                //在事务中执行目标方法
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}
}

invokeWithinTransaction方法就是Spring事务嵌入事务管理方法到业务方法前后的具体实现了。

看里面的源码就非常熟悉了,这个和编程式事务工具类TransactionTemplate的实现如出一辙,女朋友终于恍然大悟,原来是这样。

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

		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);

		//获取事务
		TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
		Object retVal = null;
		try {
			//执行目标方法crud
			retVal = invocation.proceedWithInvocation();
		}
		catch (Throwable ex) {
			// crud执行异常回滚事务
			completeTransactionAfterThrowing(txInfo, ex);
			throw ex;
		}
		finally {
			cleanupTransactionInfo(txInfo);
		}
		//提交事务
		commitTransactionAfterReturning(txInfo);
		return retVal;
		
	}
}

看到这里,其实Spring声明式事务的实现思路非常清晰了,无非就是借助Spring的AOP能力,内置了一个切面,并且在事务方法前后织入了事务管理的操作。 女朋友非常高兴,今天我的晚餐又可以加鸡腿了
在这里插入图片描述
彩蛋
能够看到这里的朋友真的是非常感激,我相信技术的力量是无穷的。 最后给大家一个安利,Spring事务虽然封装好了,一个注解就可以完成事务的功能,但是有没有一种可能?你的功能需要感知你的业务代码的事务是成功还是失败了?

Spring团队想到了这种可能,提供了一个口子给我们,这个就是事务同步器!!!,事务同步器是异步的,他会在事务提交前后通知到你,只要继承下面的抽象类即可。

public abstract class TransactionSynchronizationAdapter implements TransactionSynchronization, Ordered {

   @Override
   public int getOrder() {
      return Ordered.LOWEST_PRECEDENCE;
   }

   @Override
   public void suspend() {
   }

   @Override
   public void resume() {
   }

   @Override
   public void flush() {
   }

   @Override
   public void beforeCommit(boolean readOnly) {
   }

   @Override
   public void beforeCompletion() {
   }

   @Override
   public void afterCommit() {
   //这里可以感知事务提交完成
   }

   @Override
   public void afterCompletion(int status) {
   //这里感知事务完成
   }

}

哈哈哈,这个实现有没有很优雅,每次看Spring的组件都会在心里给Spring团队的大神点赞,封装好组件给我们用,同时提供扩展点给我们,真的非常给力。

看到这个地方的朋友,有没有觉得可以get到一点新姿势新技能,有的话麻烦一键三连,哈哈哈哈。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring事务原理是通过AOP(面向切面编程)和代理模式来实现的。Spring使用了动态代理技术,将事务管理逻辑织入到目标方法中,从而实现对事务的控制。 具体来说,Spring事务原理包括以下几个关键点: 1. 事务管理器(Transaction Manager):Spring通过事务管理器来管理事务的提交、回滚和连接的关闭等操作。事务管理器可以是JDBC事务管理器、Hibernate事务管理器或者JTA事务管理器等。 2. 事务定义(Transaction Definition):事务定义包括事务的隔离级别、传播行为、超时时间等属性。通过事务定义,我们可以指定事务的一些行为特性。 3. 事务切面(Transaction Aspect):Spring使用AOP来实现事务的切面,将事务管理逻辑织入到目标方法中。在方法执行前后,事务切面会根据事务定义来决定是否开启、提交或回滚事务。 4. 事务通知(Transaction Advice):事务通知是事务切面的具体实现,它定义了在目标方法执行前后需要执行的逻辑。在事务通知中,可以通过事务管理器来控制事务的提交、回滚等操作。 5. 事务代理(Transaction Proxy):Spring使用动态代理技术来生成事务代理对象。事务代理对象包装了目标对象,并在目标方法执行前后调用事务通知。 通过以上几个关键点的组合,Spring实现了对事务的管理和控制。当我们在业务方法上添加@Transactional注解时,Spring会根据注解的配置来生成事务代理对象,并在方法执行前后执行事务通知,从而实现对事务的管理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值