Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战

这篇具有很好参考价值的文章主要介绍了Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

在现代软件开发中,事务处理是必不可少的一部分。当多个操作需要作为一个整体来执行时,事务可以确保数据的完整性和一致性,并避免出现异常和错误情况。在SpringBoot框架中,我们可以使用声明式事务和编程式事务来管理事务处理。其中事务的坑也是不少,比较常见的就是事务失效,大家可以看看!后面小编在出一篇事务失效场景哈,喜欢的可以关注,等待更新哈!

这篇博客将重点探讨这两种事务处理方式的源码实现、区别、优缺点、适用场景以及实战。
我们来接着说事务,里面还涉及到三个知识点,大家可以自行百度好好了解!

  • 事务的特性
  • 事务的传播行为
  • 隔离级别

本篇文章主要讲的就是实现事务的两种方式的分析!

让我们开始探索声明式事务和编程式事务吧!

文章很长,耐心看完希望对你有帮助!

本文源码是使用:springboot2.7.1

二、开启使用和大致源码实现

1. 开启使用

我们在启动类上添加注解:@EnableTransactionManagement

后续使用就可以添加注解@Transactional(rollbackFor = Exception.class)使用,或者是使用编程式事务使用了 !
后面我们在详细演示怎么使用哈!

2. 声明式事务源码

public class TransactionInterceptor extends TransactionAspectSupport 
	implements MethodInterceptor, Serializable{}

TransactionInterceptor UML图:
Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战

声明式事务主要是通过AOP实现,主要包括以下几个节点:

  1. 启动时扫描@Transactional注解:在启动时,Spring Boot会扫描所有使用了@Transactional注解的方法,并将其封装成TransactionAnnotationParser对象。

  2. AOP 来实现事务管理的核心类依然是 TransactionInterceptor。TransactionInterceptor 是一个拦截器,用于拦截使用了 @Transactional 注解的方法

  3. 将TransactionInterceptor织入到目标方法中:在AOP编程中,使用AspectJ编写切面类,通过@Around注解将TransactionInterceptor织入到目标方法中

  4. 在目标方法执行前创建事务:在目标方法执行前,TransactionInterceptor会调用PlatformTransactionManager创建一个新的事务,并将其纳入到当前线程的事务上下文中。

  5. 执行目标方法:在目标方法执行时,如果发生异常,则将事务状态标记为ROLLBACK_ONLY;否则,将事务状态标记为COMMIT

  6. 提交或回滚事务:在目标方法执行完成后,TransactionInterceptor会根据事务状态(COMMIT或ROLLBACK_ONLY)来决定是否提交或回滚事务。

源码:

@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, new CoroutinesInvocationCallback() {
		@Override
		@Nullable
		public Object proceedWithInvocation() throws Throwable {
			return invocation.proceed();
		}
		@Override
		public Object getTarget() {
			return invocation.getThis();
		}
		@Override
		public Object[] getArguments() {
			return invocation.getArguments();
		}
	});
}

下面是核心处理方法,把不太重要的代码忽略了,留下每一步的节点。

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
	final InvocationCallback invocation) throws Throwable {
	// 获取事务属性
	final TransactionManager tm = determineTransactionManager(txAttr);
	// 准备事务
	TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
	// 执行目标方法
	Object retVal = invocation.proceedWithInvocation();
	 // 回滚事务
	completeTransactionAfterThrowing(txInfo, ex);
	// 提交事务
	commitTransactionAfterReturning(txInfo);
}		

3. 编程式事务源码

编程式事务主要下面的代码:

public class TransactionTemplate extends DefaultTransactionDefinition
	implements TransactionOperations, InitializingBean{}

TransactionTemplate UML图:

Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战

TransactionTemplate类的execute()方法封装了事务的具体实现,通过调用TransactionCallback对象的doInTransaction()方法来执行业务逻辑并管理事务。在具体实现中,TransactionTemplate类会自动控制事务的提交和回滚,并将异常抛出给上层调用者进行处理。

@Override
@Nullable
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
	Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");

	if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
		return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
	}
	else {
		TransactionStatus status = this.transactionManager.getTransaction(this);
		T result;
		try {
			result = action.doInTransaction(status);
		}
		catch (RuntimeException | Error ex) {
			// Transactional code threw application exception -> rollback
			rollbackOnException(status, ex);
			throw ex;
		}
		catch (Throwable ex) {
			// Transactional code threw unexpected exception -> rollback
			rollbackOnException(status, ex);
			throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
		}
		this.transactionManager.commit(status);
		return result;
	}
}

三、两者区别

上面说了源码里的大体实现,下面我们来介绍一下两者区别:

  1. 技术实现方式:声明式事务是通过AOP技术来实现的,而编程式事务是通过编写具体的代码来实现的。
  2. 代码耦合度:声明式事务可以将事务处理逻辑从业务代码中分离出来,从而降低代码的耦合度。而编程式事务需要在业务代码中显式地调用事务管理代码,因此会增加代码的耦合度。
  3. 难易程度:声明式事务相对来说比较容易上手,开发人员只需要学习注解或XML配置即可。而编程式事务需要开发人员理解事务管理的底层机制,并编写具体的代码。
  4. 性能影响:由于声明式事务是由容器来处理的,所以在一些场景下可能会对性能产生影响,大事务会有很多问题(下面在说一下大事务出现的问题)。而编程式事务由于直接调用事务管理API,相对来说会有更好的性能表现。

总体而言,声明式事务和编程式事务都有各自的优缺点,开发人员需要根据具体需求选择适合的方式来控制事务。

补充:

大事务时间过长可能会导致以下问题:
数据库锁定:当事务涉及到大量的数据操作时,事务可能会占用数据库资源并长时间锁定相关数据。这可能会导致其他事务无法访问或修改这些数据,从而降低系统的并发性能和吞吐量。
资源耗尽:长时间运行的事务需要占用更多的系统资源,如内存和CPU等。如果系统资源不足,可能会导致系统出现延迟、死锁等问题,甚至导致系统崩溃。
事务失败概率增加:当事务时间过长时,事务执行期间可能会发生各种错误,如网络故障、硬件故障、操作系统问题等。此时,事务可能无法成功提交,导致数据丢失或数据不一致。
应用程序超时:应用程序通常会为每个事务设置一个超时时间,以避免事务持续时间过长。如果事务持续时间超过设定的超时时间,则应用程序可能会因为等待事务完成而阻塞,最终导致应用程序崩溃或超时。
回滚时间增加:如果事务失败需要回滚,长时间运行的事务将需要更长的时间来进行回滚操作。这可能会导致数据不一致或丢失,并增加数据库维护的工作量。
因此,开发人员应该尽量避免事务时间过长,合理地设置事务范围、优化事务操作方式以及减少数据访问次数等措施,以提高系统的并发性能和吞吐量。

方案:
大事务可以拆分小的事务,一下查询方面的可以提取出来,操作数据库的抽离出来专门加上事务。
也可以使用CompletableFuture组合式异步编排来解决大事务的问题!!

四、优缺点

1. 声明式事务

声明式事务通常通过AOP技术实现,在方法或类级别上声明事务属性。
声明式事务的优点包括:

简化代码:开发人员只需要关注业务逻辑,而无需手动管理事务,可以减少代码复杂度和工作量。
可配置性强:事务属性可以通过XML文件、注解等方式进行配置,灵活方便。
易于扩展:可以通过AOP技术轻松地扩展使其支持新的事务策略。

声明式事务存在以下缺点:

限制较大:事务属性需要在方法或类级别进行声明,这可能会导致某些情况下难以满足特定的业务需求。
难以调试:由于事务是在AOP层面进行管理的,因此在调试时可能难以追踪事务管理的具体细节。

2. 编程式事务

编程式事务通常通过API接口实现,开发人员可以在代码中显式地管理事务。
编程式事务的优点包括:

灵活性强:开发人员可以在代码中根据具体业务需要来控制事务的具体范围和属性。
易于调试:由于事务管理在代码层面上实现,因此开发人员可以很容易地追踪事务管理的细节。

编程式事务存在以下缺点:

代码复杂度高:需要在代码中手动处理事务,并处理各种异常情况,可能会增加代码的复杂度和工作量。
可配置性差:事务的范围和属性需要在代码中显式声明,这可能会导致一些特定的业务需求难以满足。

总之,声明式事务和编程式事务各有优缺点。开发人员需要根据具体业务需求和场景选择使用合适的事务管理方式。

五、使用场景

声明式事务通常适用于以下场景:

  • 大型企业级应用程序,需要管理多个事务。
  • 代码结构比较复杂,使用声明式事务可以更好地管理和维护代码(大事务参考上方的方案)。
  • 声明式事务可以将事务管理与业务逻辑分离,从而使得应用程序更加松耦合。

而编程式事务通常适用于以下场景:

  • 需要更精确地控制事务的范围和处理逻辑。
  • 编程式事务通常比声明式事务更加灵活,可以根据业务逻辑的需要来自定义事务的范围、隔离级别以及回滚机制等。
  • 在某些高并发场景下,可以使用编程式事务仅针对需要操作的数据进行锁定,而不是对整个业务逻辑加事务。

在实际场景中,可以根据需求综合考虑使用声明式事务和编程式事务的优势来进行选择。

根据不同的用户量来具体选择,在几乎没有并发量的系统设计一条异步编排反而大材小用,可能造成资源的浪费;但是有需要等待远程API的响应时,使用异步编排可以将等待时间最小化,并使得应用程序不必阻塞等待API响应,从而提高用户体验。

很多事情没有绝对化,只有相对化,只要能支持现有正常的使用,不管什么样的设计都是没问题的!
可能好的设计会使系统在经受并发量增大的过程中无感,还是要调研清楚,从而设计出更好的方案,防止资源浪费!

尽管小编还没有什么架构经验,但还是对架构充满兴趣,不想做架构师的开发不是好开发哈!!当然你也可以走管理!!

六、实战

1. 声明式事务

这里就简单模拟一下,为了模拟报错,把OperIp设置为唯一!

@Transactional(rollbackFor = Exception.class)大家经常使用,就不多演示了!

@Transactional(rollbackFor = Exception.class)
@Override
public void template() {
    SysLog sysLog = new SysLog();
    sysLog.setOperIp("123");
    SysLog sysLog1 = new SysLog();
    sysLog1.setOperIp("hhh");
    log.info("插入第一条数据开始========");
    testMapper.insert(sysLog);
    log.info("插入第一条数据完成========");
    log.info("插入第二条数据开始========");
    testMapper.insert(sysLog);
    log.info("插入第二条数据完成========");

}

此时数据没有数据,全部回滚成功!

Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战

2. 编程式事务

首先注入TransactionTemplate

@Autowired
private TransactionTemplate transactionTemplate;

后面直接使用即可:

@Override
public void template() {
    SysLog sysLog = new SysLog();
    sysLog.setOperIp("123");
    SysLog sysLog1 = new SysLog();
    sysLog1.setOperIp("hhh");
    log.info("插入第一条数据开始========");
    testMapper.insert(sysLog);
    log.info("插入第一条数据完成========");

    transactionTemplate.execute(status -> {
        log.info("编程式事务中:插入第一条数据开始========");
        testMapper.insert(sysLog1);
        log.info("编程式事务中:插入第一条数据完成========");
        log.info("编程式事务中:插入第二条数据开始========");
        int insert = testMapper.insert(sysLog);
        log.info("编程式事务中:插入第二条数据完成========");
        return insert;
    });
}

Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战
查看数据库,第一条不在编程式事务内不会参与回滚!
Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战

七、总结

本文介绍了SpringBoot框架中的声明式事务和编程式事务,并分析了它们的源码实现、区别、优缺点、适用场景以及实战。
无论是采用哪种方式来管理事务,都需要考虑到业务需求和开发团队的实际情况,选择合适的事务处理方式,以确保系统的可靠性和稳定性。

希望通过本文的介绍,你能够更好地理解声明式事务和编程式事务的概念和原理,在开发过程中选择合适的事务处理方式,提高项目的可维护性和稳定性。


如果对你有帮助,还请动一下您的发财小手,关注一下公众号哈!!谢谢您的关注!!文章首发看!!!

建了一个IT交流群,欢迎大家加入,过期加我拉你们进哈!

Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战文章来源地址https://www.toymoban.com/news/detail-741241.html

到了这里,关于Spring/SpringBoot中的声明式事务和编程式事务源码、区别、优缺点、适用场景、实战的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Springboot 编程式事务

    spring-boot 2.5.3版本 msyql SpringBoot编程式事务,可以使用2种方式。 默认TransactionAutoConfiguration自动装配。使用时直接注入TransactionTemplate 使用 推荐使用 编写一个测试类,简单测试一下,测试一下异常报错,手动设置回滚状态。 控制台打印 spring提供了TransactionCallback和子类Transac

    2024年02月11日
    浏览(41)
  • 32、启用 HTTP 响应压缩和编程式配置Web应用

    就是前端页面如果改动的比较多,那么响应就会比较慢,可以通过设置HTTP响应压缩来提高响应,如果前端改动少,那么就不需要启动这个响应压缩。 就是获取到 WebServer 这个Web服务器,然后修饰里面的一些东西,比如端口号,比如对某些前端页面启用 HTTP压缩 的功能。 方法

    2024年02月11日
    浏览(51)
  • 【Spring 事务详解】声明式事务概念

    个人名片: 🐼 作者简介:一名大三在校生,喜欢AI编程🎋 🐻‍❄️ 个人主页🥇: 落798. 🐼 个人WeChat:hmmwx53 🕊️ 系列专栏:🖼️ 零基础学Java——小白入门必备🔥 重识C语言——复习回顾🔥 计算机网络体系———深度详讲 HCIP数通工程师-刷题与实战🔥🔥🔥 微信小程

    2024年04月12日
    浏览(45)
  • Spring声明式事务(Spring学习笔记十三)

            不推荐使用编程式事务  在Spring-dao.xml中配置声明式事务  结合aop实现事务的织入 分两步         第一步:          第二步:

    2024年04月10日
    浏览(38)
  • Spring 声明式事务 @Transactional(基本使用)

            声明式事务的实现很简单,只需要在需要事务的⽅法上添加 @Transactional 注解就可以实现了.⽆需⼿动开启事务和提交事务,进⼊⽅法时⾃动开启事务,⽅法执⾏完会⾃动提交事务,如果中途发⽣了 没有处理的异常会⾃动回滚事务.         废话不多说,直接看代码实现,

    2024年01月23日
    浏览(49)
  • 14、Spring之基于注解的声明式事务

    事务功能的相关操作全部通过自己编写代码来实现: 编程式事务的缺陷: 细节没有被屏蔽:所有细节都需要程序员自己来完成,比较繁琐。 代码复用性不高:每次实现功能都需要自己编写代码,代码没有得到复用。 因为事务控制的代码有规律可循,代码的结构基本是确定的

    2024年02月10日
    浏览(40)
  • Spring Boot原理分析(四):声明式事务

    Spring 提供了多种管理事务的方式,包括编程式事务管理和声明式事务管理两种方式。下面分别介绍这两种方式及其实现方式: 编程式事务管理是通过编写代码来手动管理事务。它需要在事务的开始和结束时,通过编程方式来控制事务的提交和回滚。Spring 提供了 PlatformTransa

    2024年02月17日
    浏览(48)
  • Spring 事务的相关配置、传播行为、隔离级别及注解配置声明式事务

    目录 一、事务的相关配置 1. 添加测试标签 2. 添加对应方法 3. 测试 二、事务的传播行为 三、事务的隔离级别 四、注解配置声明式事务 1. 注册事务注解驱动 2. 加上注解 3. 配置类代替xml文件中的注解事务支持 4. 测试 往期专栏文章相关导读  1. Maven系列专栏文章 2. Mybatis系列专

    2024年02月08日
    浏览(44)
  • 15、Spring之基于xml的声明式事务

    阅读本文前,建议先阅读Spring之基于注解的声明式事务 创建名为spring_transaction_xml的新module,过程参考13.1节 注意:比起基于注解的声明式事务,基于xml的声明式事务还需要额外引入spring-AOP的依赖 注意:因为控制层没用到接口,所以方法的访问修饰符要手动设置 注意:tx:ad

    2024年02月10日
    浏览(33)
  • Spring 声明式事务不生效的问题如何解决

    Spring 声明式事务不生效的问题如何解决 Spring 的声明式事务通常使用 @Transactional 注解来实现。如果你发现声明式事务不生效,可能有几个原因导致这种情况。以下是一些可能的解决方法: 确保配置正确 : 确保在 Spring 的配置文件(如 applicationContext.xml)中启用了事务管理器

    2024年02月21日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包