Spring Boot中的事务是如何实现的?懂吗?

SpringBoot中的事务管理,用得好,能确保数据的一致性和完整性;用得不好,可能会给性能带来不小的影响哦。

基本使用

在SpringBoot中,事务的使用非常简洁。首先,得感谢Spring框架提供的@Transactional注解,这个小东西可以说是非常强大了。

让我们先看一个基础的例子:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Transactionalpublic void createUser(String name) {User user = new User(name);userRepository.save(user);// 这里假设有其他的逻辑操作}
}

在这个例子中,我们通过@Transactional注解标记了createUser方法。这意味着,当这个方法被调用时,Spring会为我们自动创建一个事务。如果方法正常执行完毕,事务就会提交;如果遇到异常,事务就会回滚,确保数据的一致性。

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。

这是大佬写的, 7701页的BAT大佬写的刷题笔记,让我offer拿到手软

开启事务

虽然我们已经看到了如何使用@Transactional,但是你知道Spring是如何开启事务的吗?其实,当我们使用@Transactional注解时,Spring会通过AOP(面向切面编程)在运行时创建代理对象,来管理事务的开启和关闭。这个过程对我们来说是透明的,但了解其背后的机制对于深入理解Spring事务是很有帮助的。

事务回滚

默认情况下,如果被@Transactional注解的方法抛出了运行时异常(RuntimeException)或者Error,Spring就会回滚事务。但是,如果你想让事务在遇到非运行时异常时也回滚,可以这样做:

@Transactional(rollbackFor = Exception.class)
public void createUserWithRollbackForException(String name) throws Exception {// ...
}

性能优化

事务虽好,但也不是没有成本的。在某些高并发场景下,过多的事务操作可能会成为性能瓶颈。为了优化性能,我们可以通过以下几种方式:

  1. 减少事务范围:尽量让事务只包含那些必须要在同一事务中完成的操作。
  2. 只读事务:如果事务只涉及到数据的读取,可以将事务标记为只读,这样可以帮助数据库优化事务处理。
@Transactional(readOnly = true)
public User findUserById(Long id) {return userRepository.findById(id).orElse(null);
}

失效场景

在使用Spring事务的时候,有些情况可能会导致事务失效,比如:

  1. 自调用问题:在同一个类中,一个非事务方法调用事务方法,事务是不会起作用的。
  2. 异常处理:如果你在事务方法中捕获了所有异常,并没有重新抛出,事务是不会回滚的。

使用场景

事务通常用在需要保证一系列操作要么全部成功,要么全部失败的场景,比如:

  • 用户注册时,需要同时创建用户记录和用户的初始数据。
  • 订单支付时,需要更新订单状态和用户的账户余额。

代码示例

让我们再看一个例子,模拟用户转账的场景:

@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {User fromUser = userRepository.findById(fromId).orElseThrow();User toUser = userRepository.findById(toId).orElseThrow();fromUser.setBalance(fromUser.getBalance().subtract(amount));toUser.setBalance(toUser.getBalance().add(amount));userRepository.save(fromUser);userRepository.save(toUser);
}

在这个例子中,我们通过事务确保了转账操作的原子性。如果在转账过程中发生任何异常,比如余额不足,整个操作都会回滚,保证账户的数据一致性。

SpringBoot中事务管理的一些更高级和具体的应用场景

示例1:声明式事务的传播行为

Spring事务的传播行为定义了事务方法之间的交互方式。举个例子,我们来看REQUIREDREQUIRES_NEW传播行为的区别。

@Service
public class AccountService {@Autowiredprivate TransferService transferService;@Transactional(propagation = Propagation.REQUIRED)public void methodA() {// 这里的操作在methodA的事务范围内transferService.methodB();// 如果methodB出错,整个methodA都会回滚}@Transactional(propagation = Propagation.REQUIRES_NEW)public void methodB() {// 这里的操作有自己的独立事务// 即使methodA失败了,methodB的操作还是会提交}
}

示例2:编程式事务管理

除了声明式事务,Spring还支持编程式事务管理,这在某些复杂的场景下非常有用。

@Service
public class ComplexService {@Autowiredprivate TransactionTemplate transactionTemplate;public void executeComplexLogic() {transactionTemplate.execute(new TransactionCallback<Void>() {@Overridepublic Void doInTransaction(TransactionStatus status) {// 这里是你的业务逻辑// 如果需要回滚,可以调用 status.setRollbackOnly();return null;}});}
}

示例3:事务的隔离级别

事务的隔离级别决定了一个事务可能受其他并发事务影响的程度。比如,我们来看看如何设置隔离级别:

@Transactional(isolation = Isolation.SERIALIZABLE)
public void transferMoney(Long fromAccountId, Long toAccountId, BigDecimal amount) {// 这个方法会以最高的隔离级别运行,以避免并发事务带来的问题// 但是性能可能会受影响
}

示例4:事务超时设置

在某些长时间运行的事务中,你可能需要设置事务的超时时间,以避免长时间占用资源。

@Transactional(timeout = 10) // 10秒超时
public void processLargeData() {// 这个方法如果运行超过10秒,事务会被标记为回滚
}

示例5:事务回滚的条件自定义

有时候,你可能需要自定义事务回滚的条件。比如,只在特定的异常出现时才回滚。

@Transactional(rollbackFor = {CustomException.class})
public void updateUserDetails(User user) throws CustomException {// 这个方法只在CustomException抛出时才回滚// 其他异常不会触发回滚
}

示例6:嵌套事务

嵌套事务允许在一个事务内部开始一个新的事务。如果内部事务失败,它会回滚到它开始的状态,而不影响外部事务。

@Transactional
public void parentMethod() {// 父事务的操作...try {nestedMethod();} catch (Exception e) {// 处理内部事务异常,父事务可以继续}// 父事务的其他操作...
}@Transactional(propagation = Propagation.NESTED)
public void nestedMethod() {// 嵌套事务的操作...
}

示例7:声明式事务与异常处理

处理声明式事务时,异常的处理方式至关重要。下面是一个常见的错误处理方式。

@Transactional
public void updateUser() {try {// 更新用户数据的操作...} catch (Exception e) {// 捕获异常,这将导致事务不回滚}
}

在这个例子中,由于异常被捕获并没有重新抛出,事务将不会回滚,这可能会导致数据的不一致性。

示例8:使用事务同步管理器

在某些情况下,你可能需要直接与事务同步管理器进行交互,以获取当前事务的状态信息。

public void complexBusinessLogic() {boolean isCurrentTransactionActive = TransactionSynchronizationManager.isActualTransactionActive();if (isCurrentTransactionActive) {// 执行依赖于当前事务的操作...}
}

示例9:异步方法与事务

异步方法和事务一起使用时需要特别小心,因为异步方法通常会在不同的线程中运行,这可能会导致事务管理出现问题。

@Async
@Transactional
public Future<String> asyncMethodWithTransaction() {// 异步操作,但事务可能不会按预期工作// 因为它可能在不同的线程中执行return new AsyncResult<>("Done");
}

示例10:事务日志记录

在某些业务场景中,你可能需要记录事务的执行情况,特别是在事务提交或回滚时。

@Transactional
public void transactionalMethodWithLogging() {// 事务操作...TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {@Overridepublic void afterCommit() {// 记录事务提交后的日志}@Overridepublic void afterCompletion(int status) {if (status == TransactionSynchronization.STATUS_ROLLED_BACK) {// 记录事务回滚的日志}}});
}

通过这些示例,你可以看到Spring事务管理在不同场景下的应用。

理解这些复杂场景对于能够在实际开发中灵活运用Spring事务管理至关重要。

记住,每个场景都有其特殊性,选择正确的事务策略可以帮助你避免许多常见的问题。

核心要点

  1. 基本使用:使用@Transactional注解来声明事务,这是Spring提供的一种声明式事务管理方式。
  2. 事务传播行为:Spring事务的传播行为定义了事务之间的相互作用,如REQUIREDREQUIRES_NEWNESTED等,这决定了事务是否共享或独立。
  3. 事务的隔离级别:隔离级别(如READ_COMMITTEDSERIALIZABLE等)控制事务之间的可见性,防止诸如脏读、不可重复读、幻读等问题。
  4. 事务的回滚规则:默认情况下,Spring仅在运行时异常发生时回滚事务。可通过rollbackFor自定义回滚条件。
  5. 超时和只读设置:可以设置事务的超时时间和声明只读事务,以优化性能和资源利用。

高级应用场景

  1. 编程式事务管理:通过TransactionTemplate或直接使用PlatformTransactionManager来手动管理事务。
  2. 嵌套事务:通过NESTED传播行为实现嵌套事务,内部事务失败不影响外部事务。
  3. 异步和事务:异步方法中使用事务需要特别注意,由于执行线程的不同,可能影响事务的管理。
  4. 事务同步管理:使用TransactionSynchronizationManager进行事务的细粒度控制,如在事务提交或回滚后执行特定操作。
  5. 异常处理与事务回滚:异常处理在事务中非常重要,不当的异常处理可能导致事务不回滚,引起数据不一致。

实际应用建议

  • 合理设计事务范围:避免将大量操作包含在单一事务中,以减少资源锁定时间和提高性能。
  • 注意异常处理:确保适当的异常抛出,以触发事务回滚。
  • 避免在异步方法中使用事务:或者确保你理解如何在多线程环境下正确管理事务。
  • 谨慎使用嵌套事务:它们可能会增加复杂性和性能开销。
  • 监控和调优:在生产环境中监控事务的性能,根据需要调整事务策略和配置。

总之,SpringBoot中的事务管理是一个强大但需要谨慎使用的工具。

理解它的工作原理和应用场景,可以帮助你更有效地管理数据一致性和应用性能。

记住,每个应用的需求不同,所以在使用事务时,总是要考虑到你的具体场景和需求。

最后说一句(求关注,求赞,别白嫖我)

最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。

这是大佬写的, 7701页的BAT大佬写的刷题笔记,让我offer拿到手软

项目文档&视频:

项目文档 & 视频

本文,已收录于,我的技术网站 ddkk.com,有大厂完整面经,工作技术,架构师成长之路,等经验分享

求一键三连:点赞、分享、收藏

点赞对我真的非常重要!在线求赞,加个关注我会非常感激

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/264500.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

四. 基于环视Camera的BEV感知算法-环视背景介绍

目录 前言0. 简述1. 环视背景介绍2. 环视思路3. 主流基于环视Camera的算法详解总结下载链接参考 前言 自动驾驶之心推出的《国内首个BVE感知全栈系列学习教程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习下课程第四章——基于环视Camer…

Docker Compose(容器编排)——9

目录 什么是 Docker Compose生活案例为什么要 Docker ComposeDocker Compose 的安装Docker Compose 的功能Docker Compose 使用场景Docker Compose 文件&#xff08;docker-compose.yml&#xff09; 文件语法版本文件基本结构及常见指令Docker Compose 命令清单 命令清单如下命…

Cocos Creator:创建棋盘

Cocos Creator&#xff1a;创建棋盘 创建地图三部曲&#xff1a;1. 创建layout组件2. 创建预制体Prefab&#xff0c;做好精灵贴图&#xff1a;3. 创建脚本LayoutSprite.ts收尾工作&#xff1a; 创建地图三部曲&#xff1a; 1. 创建layout组件 使用layout进行布局&#xff0c;…

Qt设置类似于qq登录页面

头文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QWindow> #include <QIcon> #include <QLabel> #include <QMovie> #include <QLineEdit> #include <QPushButton>QT_BEGIN_NAMESPACE namespace Ui { class…

【Matlab算法】多维函数求解的基本概念

多维函数求解的基本概念 多维函数最优化问题最优化算法最优化问题的类型最优化算法的分类常用的多维函数求解方法结语 多维函数 多维函数是指定义在 R n \mathbb{R}^n Rn 上的函数&#xff0c;其中 n n n 是函数的维数。例如&#xff0c; f ( x , y ) x 2 y 2 f(x, y) x^…

halcon视觉缺陷检测常用的6种方法

一、缺陷检测综述 缺陷检测是视觉需求中难度最大一类需求,主要是其稳定性和精度的保证。首先常见缺陷:凹凸、污点瑕疵、划痕、裂缝、探伤等。常用的手法有六大金刚(在halcon中的ocv和印刷检测是针对印刷行业的检测,有对应算子封装): 1.blob+特征 2.blob+差分+特征 3.光度…

JVM 内存分析工具 Memory Analyzer Tool(MAT)的深度讲解

目录 一. 前言 二. MAT 使用场景及主要解决问题 三. MAT 基础概念 3.1. Heap Dump 3.2. Shallow Heap 3.3. Retained Set 3.4. Retained Heap 3.5. Dominator Tree 3.6. OQL 3.7. references 四. MAT 功能概述 4.1. 内存分布 4.2. 对象间依赖 4.3. 对象状态 4.4…

〖大前端 - 基础入门三大核心之JS篇㊿〗- 面向对象之对象的方法、遍历、深浅克隆

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;哈哥撩编程&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xff0c;目前在公司…

python:五种算法(DBO、WOA、GWO、PSO、GA)求解23个测试函数(python代码)

一、五种算法简介 1、蜣螂优化算法DBO 2、鲸鱼优化算法WOA 3、灰狼优化算法GWO 4、粒子群优化算法PSO 5、遗传算法GA 二、5种算法求解23个函数 &#xff08;1&#xff09;23个函数简介 参考文献&#xff1a; [1] Yao X, Liu Y, Lin G M. Evolutionary programming made…

一文掌握Ascend C孪生调试

1 What&#xff0c;什么是孪生调试 Ascend C提供孪生调试方法&#xff0c;即CPU域模拟NPU域的行为&#xff0c;相同的算子代码可以在CPU域调试精度&#xff0c;NPU域调试性能。孪生调试的整体方案如下&#xff1a;开发者通过调用Ascend C类库编写Ascend C算子kernel侧源码&am…

SQL语句的执行顺序怎么理解?

SQL语句的执行顺序怎么理解&#xff1f; 我们常常会被SQL其书写顺序和执行顺序之间的差异所迷惑。理解这两者的区别&#xff0c;对于编写高效、可靠的SQL代码至关重要。今天&#xff0c;让我们用一些生动的例子和场景来深入探讨SQL的执行顺序。 一、书写顺序 VS 执行顺序 SQ…

为 Compose MultiPlatform 添加 C/C++ 支持(2):在 jvm 平台使用 jni 实现桌面端与 C/C++ 互操作

前言 在上篇文章中我们已经介绍了实现 Compose MultiPlatform 对 C/C 互操作的基本思路。 并且先介绍了在 kotlin native 平台使用 cinterop 实现与 C/C 的互操作。 今天这篇文章将补充在 jvm 平台使用 jni。 在 Compose MultiPlatform 中&#xff0c;使用 jvm 平台的是 An…