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 {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public 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 {

    @Autowired
    private 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 {

    @Autowired
    private TransactionTemplate transactionTemplate;

    public void executeComplexLogic() {
        transactionTemplate.execute(new TransactionCallback<Void>() {
            @Override
            public 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() {
            @Override
            public void afterCommit() {
                // 记录事务提交后的日志
            }

            @Override
            public 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.mfbz.cn/a/234576.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Proteus仿真--串口发送数据到2片8×8点阵屏滚动显示

本文介绍2片88点阵屏滚动显示设计&#xff08;完整仿真源文件及代码见文末链接&#xff09; 仿真图如下 仿真运行视频 Proteus仿真--1602LCD显示电话拨号键盘按键实验&#xff08;仿真文件程序&#xff09; 附完整Proteus仿真资料代码资料 链接&#xff1a;https://pan.baidu…

Leetcode每日一题

https://leetcode.cn/problems/binary-tree-preorder-traversal/ 这道题目需要我们自行进行创建一个数组&#xff0c;题目也给出我们需要自己malloc一个数组来存放&#xff0c;这样能达到我们遍历的效果&#xff0c;我们来看看他的接口函数给的是什么。 可以看到的是这个接口函…

qt可以详细写的项目或技术

1.QT 图形视图框架 2.QT 模型视图结构 3.QT列表显示大量信息 4.QT播放器 5.QT 编解码 6.QT opencv

2023北京智慧城市与电气高峰论坛-安科瑞 蒋静

2023年7月27日&#xff0c;北京土木建筑学会电气设计委员会、北京电气设计技术协作及情报交流网联合举办的“北京电气设计第43届年会”在京盛大召开。安科瑞作为企业微电网能效管理平台服务商与广大同仁共聚本次盛会&#xff0c;尽享技术盛宴。 本次会议采用线上线下相结合&…

【C++】:红黑树

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关多态的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结…

12.视图

目录 1.视图的含义与作用 2.视图的创建与查看 1.创建视图的语法形式 2、查看视图&#xff1a; 1.使用DESCRIBE语句查看视图基本信息 2.使用SHOW TABLE STATUS语查看视图基本信息查看视图的信息 3.使用SHOW CREATE VIEW语查看视图详细信息 4.在views表中查看视图详细信息…

【合集】SpringBoot——Spring,SpringBoot,SpringCloud相关的博客文章合集

前言 本篇博客是spring相关的博客文章合集&#xff0c;内容涵盖Spring&#xff0c;SpringBoot&#xff0c;SpringCloud相关的知识&#xff0c;包括了基础的内容&#xff0c;比如核心容器&#xff0c;springMVC&#xff0c;Data Access&#xff1b;也包括Spring进阶的相关知识&…

智能优化算法应用:基于正余弦算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于正余弦算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于正余弦算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.正余弦算法4.实验参数设定5.算法结果6.参考文…

【数电笔记】54-或非门构成的基本RS触发器

目录 说明&#xff1a; 1. 电路组成 2. 逻辑功能 3. 特性表 4. 特性方程 5. 例题 6. 两种基本RS触发器的形式比 说明&#xff1a; 笔记配套视频来源&#xff1a;B站&#xff1b;本系列笔记并未记录所有章节&#xff0c;只对个人认为重要章节做了笔记&#xff1b;标题前…

NAND闪存价格暴涨:512GB芯片翻倍,256GB涨幅达55%

此前&#xff0c;根据Trendforce的信息&#xff0c;今年第四季度NAND的合约价预计上涨8-13%&#xff0c;其中Wafer上涨13-18%。 根据DRAMeXchange最新的数据表明&#xff0c;之前预测的数据还是太保守了&#xff0c;过去一年Wafer NAND价格如下图&#xff1a; DRAM/NAND价格近几…

体系化学习运筹学基础算法的实践和总结

文章目录 引言目标设计目标实践文章汇总经验总结一则预告 引言 眨眼间已经12月了&#xff0c;眼看着2023年马上要过完了。 女朋友最近总说&#xff0c;工作以后感觉时间过的好快。事实上&#xff0c;我也是这么认为的。年纪越大&#xff0c;越会担心35岁危机的降临。所以&…

CESM笔记——component活动状态+compset前缀解析+B1850,BHIST区别

时隔一年没写CSDN笔记了&#xff0c;一些CESM的知识点我都快忘了。诶&#xff0c;主要是在国外办公室的网屏蔽了好多国内的网络&#xff0c;CSDN登不上&#xff0c;回家又不想干活。。。好吧&#xff0c;好多借口。。。 昨天师弟问我一些问题&#xff0c;想想要不可以水一篇小…

MySQL进阶学习--day01

存储引擎介绍 1. MySQL体系结构2. 存储引擎介绍2.1 存储引擎操作2.2 示例演示 1. MySQL体系结构 连接层&#xff08;Connection Layer&#xff09;&#xff1a;连接层主要负责与客户端建立连接&#xff0c;并进行用户身份验证和权限验证。在这一层&#xff0c;MySQL 接收来自客…

postgresql安装部署(docker版本)

1.在线部署 创建数据库存储目录 mkdir /home/pgdata创建容器 docker run --name postgresql --restartalways -d -p 5432:5432 -v /home/pgdata:/var/lib/postgresql/data --shm-size10g -e POSTGRES_PASSWORD密码 postgis/postgis:12-3.2-alpine–name为设置容器名称 -d表…

网页设计中增强现实的兴起

目录 了解增强现实 增强现实的历史背景 AR 和网页设计的交叉点 AR 在网页设计中的优势 增强参与度和互动性 个性化的用户体验 竞争优势和品牌差异化 AR 在网页设计中的用例 结论 近年来&#xff0c;增强现实已成为一股变革力量&#xff0c;重塑了我们与数字领域互动的方式。它被…

每天五分钟计算机视觉:使用1*1卷积层来改变输入层的通道数量

本文重点 在卷积神经网络中有很多重要的卷积核&#xff0c;比如1*1的卷积核&#xff0c;3*3的卷积核&#xff0c;本文将讲解1*1的卷积核的使用&#xff0c;它在卷积神经网络中具有重要的地位。由于1*1的卷积核使用了最小的窗口&#xff0c;那么1*1的卷积核就失去了卷积层可以识…

QEMU环境调试方法

目录 1.如何查看makefile构建过程执行的命令&#xff1f; 2.如何使用GCC生成C程序的宏展开文件&#xff1f; 3.如何在qemu中执行特定的可执行程序&#xff1f; 4.如何在qemu中直接运行可执行程序&#xff1f; 5.如何在qemu中调试某个可执行程序&#xff1f; 本文从调试的角…

Linux的权限

Linux的权限 一、shell运行原理--外壳程序二、Linux权限&#xff08;主体&#xff0c;重点&#xff09;三、常见的权限问题目录权限umask粘滞位 一、shell运行原理–外壳程序 为什么我们不是直接访问的操作系统&#xff1f; 1.人不善于直接使用操作系统 2.如果让人直接访问操作…

阵列信号处理-波束方向图参数

波束方向图的参数有&#xff1a; 3dB带宽(半功率波束宽度&#xff0c;HPBW&#xff0c;half-power beamwidth)到第一零点距离(这个距离的两倍称为 B W N N BW_{NN} BWNN​)到第一旁瓣的距离第一旁瓣的高度其余零点的位置旁瓣的衰减速率栅瓣 波束方向图的主波束 3dB波束宽度 3…

reinforce 跑 CartPole-v1

gym版本是0.26.1 CartPole-v1的详细信息&#xff0c;点链接里看就行了。 修改了下动手深度强化学习对应的代码。 然后这里 J ( θ ) J(\theta) J(θ)梯度上升更新的公式是用的不严谨的&#xff0c;这个和王树森书里讲的严谨公式有点区别。 代码 import gym import torch from …