深入解析Spring Boot中的`@Transactional`注解

news/2024/9/18 15:02:22/ 标签: spring boot, 数据库, sql

一、@Transactional注解概述

1.1 什么是@Transactional

@Transactional是Spring框架中用于声明式事务管理的注解。通过在方法或类上添加@Transactional注解,Spring会自动将该方法或类中的数据库操作纳入到事务管理中,从而保证这些操作的原子性、一致性、隔离性和持久性(即ACID属性)。

1.2 @Transactional的作用

@Transactional的主要作用是管理数据库事务,它可以确保:

  • 原子性:方法中的多个数据库操作要么全部成功,要么全部失败。
  • 一致性:事务执行前后,数据库保持一致性。
  • 隔离性:事务之间相互隔离,防止并发问题。
  • 持久性:事务一旦提交,结果将永久保存到数据库中。

二、@Transactional的工作原理

2.1 基于AOP的事务管理

Spring的事务管理是基于AOP(面向切面编程)实现的。当一个方法被@Transactional注解标记时,Spring会为该方法生成一个代理对象,代理对象会在方法执行前开启事务,在方法执行完成后提交事务,如果方法抛出异常,则回滚事务。

2.2 事务传播机制

@Transactional注解中的propagation属性决定了当前事务的传播行为。Spring支持以下几种传播行为:

  • REQUIRED(默认值):如果当前存在事务,则加入该事务;如果当前没有事务,则新建一个事务。
  • REQUIRES_NEW:每次都会新建一个事务,如果当前存在事务,则挂起当前事务。
  • SUPPORTS:支持当前事务,如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
  • NOT_SUPPORTED:以非事务方式执行,如果当前存在事务,则挂起当前事务。
  • MANDATORY:必须在一个已有事务中执行,如果当前没有事务,则抛出异常。
  • NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  • NESTED:如果当前存在事务,则在嵌套事务中执行;如果当前没有事务,则新建一个事务。

2.3 事务隔离级别

@Transactional注解中的isolation属性决定了事务的隔离级别。Spring支持以下几种隔离级别:

  • DEFAULT:使用底层数据库的默认隔离级别。
  • READ_UNCOMMITTED:最低的隔离级别,可能导致脏读、不可重复读和幻读。
  • READ_COMMITTED:可以防止脏读,但仍可能出现不可重复读和幻读。
  • REPEATABLE_READ:可以防止脏读和不可重复读,但仍可能出现幻读。
  • SERIALIZABLE:最高的隔离级别,确保事务的完整性,但性能较低。

2.4 事务超时与只读设置

  • timeout属性:指定事务的超时时间,单位为秒。如果事务在指定时间内没有完成,则会回滚。
  • readOnly属性:设置事务为只读,优化数据库操作,特别是在查询操作时。

2.5 事务回滚策略

  • rollbackFor属性:指定哪些异常会导致事务回滚。默认情况下,Spring会在遇到RuntimeExceptionError时回滚事务。
  • noRollbackFor属性:指定哪些异常不会导致事务回滚。

三、@Transactional注解的实际应用

3.1 方法级别的事务管理

通常情况下,我们会在服务层(Service Layer)的方法上使用@Transactional注解,以确保这些方法中的数据库操作能够被事务管理。

@Service
public class UserService {@Autowiredprivate UserRepository userRepository;@Transactionalpublic void createUser(User user) {userRepository.save(user);// 其他业务逻辑}
}

在上述例子中,createUser方法被@Transactional注解标记,这意味着在该方法执行期间,如果出现异常,所有数据库操作都会被回滚。

3.2 类级别的事务管理

@Transactional注解也可以放在类级别,这样类中所有的public方法都会被事务管理。

@Service
@Transactional
public class UserService {@Autowiredprivate UserRepository userRepository;public void createUser(User user) {userRepository.save(user);// 其他业务逻辑}public void deleteUser(Long id) {userRepository.deleteById(id);// 其他业务逻辑}
}

在此例子中,UserService类中所有的public方法都会被事务管理。

3.3 多事务管理器

在复杂的应用中,可能会有多个数据源,此时我们需要配置多个事务管理器,并在@Transactional注解中指定使用哪个事务管理器。

@Configuration
@EnableTransactionManagement
public class DataSourceConfig {@Bean(name = "firstTransactionManager")public PlatformTransactionManager firstTransactionManager(EntityManagerFactoryBuilder builder) {return new JpaTransactionManager(firstEntityManagerFactory(builder).getObject());}@Bean(name = "secondTransactionManager")public PlatformTransactionManager secondTransactionManager(EntityManagerFactoryBuilder builder) {return new JpaTransactionManager(secondEntityManagerFactory(builder).getObject());}
}

在Service层中,可以通过@Transactional注解的transactionManager属性指定使用哪个事务管理器:

@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;@Transactional(transactionManager = "firstTransactionManager")public void processOrder(Order order) {orderRepository.save(order);// 其他业务逻辑}
}

3.4 嵌套事务

在某些情况下,我们可能需要在一个事务中嵌套另一个事务。Spring提供了NESTED事务传播行为,支持这种需求。

@Service
public class OrderService {@Autowiredprivate PaymentService paymentService;@Transactionalpublic void processOrder(Order order) {paymentService.processPayment(order);// 其他业务逻辑}
}@Service
public class PaymentService {@Transactional(propagation = Propagation.NESTED)public void processPayment(Order order) {// 支付逻辑}
}

在上述例子中,PaymentService中的processPayment方法被NESTED传播行为标记,这意味着即使processOrder方法回滚,processPayment方法的操作也可以单独回滚或提交。

四、@Transactional注解的常见问题与解决方案

4.1 @Transactional注解不生效

原因分析
  • 方法可见性问题@Transactional注解只会在public方法上生效,如果方法是private、protected或者package-private,则事务不会被代理。
  • 自调用问题:当同一个类中的方法相互调用时,如果调用者和被调用者都使用了@Transactional,Spring不会代理这种情况,导致事务不生效。
  • 配置问题:检查@EnableTransactionManagement注解是否正确配置,确保事务管理器被正确加载。
解决方案
  • 确保使用@Transactional注解的方法是public的。
  • 使用AOP配置或者将方法调用移到外部类中,以避免自调用导致的问题。
  • 确保在配置类中正确启用了事务管理。

4.2 嵌套事务回滚问题

原因分析

嵌套事务的回滚机制较为复杂,默认情况下,嵌套事务的回滚可能不会影响到外部事务,导致数据不一致。

解决方案

可以通过Propagation.NESTEDPropagation.REQUIRES_NEW来区分不同的事务边界,从而确保在出现问题时回滚到预期的事务状态。

4.3 事务隔离级别导致的性能问题

原因分析

高隔离级别(如SERIALIZABLE)会显著降低数据库的并发性能,导致系统吞吐量下降。

解决方案

在实际应用中,应该根据业务需求选择合适的事务隔离级别,避免不必要的高隔离级别配置。同时,优化数据库索引和查询策略,减少锁冲突。

五、总结

@Transactional是Spring Boot中一个非常强大的注解,它简化了事务管理

,使得开发者可以专注于业务逻辑的实现。然而,在实际应用中,合理地使用@Transactional注解并避免常见的坑,仍然是一个需要深入理解和持续实践的过程。希望本文能够帮助你更好地掌握@Transactional注解的使用,并在项目中发挥其最大价值。


通过理解Spring Boot中的@Transactional注解,你可以更好地掌握事务管理的原理,并在实际开发中应用这些知识来编写健壮的、易维护的代码。


http://www.ppmy.cn/news/1521046.html

相关文章

ES6中try-catch

在ES6(ECMAScript 2015)中,try-catch 语句的语法和使用方式与在之前的ECMAScript版本中是一样的。try-catch 语句用于处理代码中可能发生的错误,确保程序的健壮性和用户体验。 基本语法 try { // 尝试执行的代码块 // 如果发生…

Chrome 浏览器插件获取网页 window 对象(方案二)

前言 最近有个需求,是在浏览器插件中获取 window 对象下的某个数据,当时觉得很简单,和 document 一样,直接通过嵌入 content_scripts 直接获取,然后使用 sendMessage 发送数据到插件就行了,结果发现不是这…

TCP如何关闭连接(详细版)

关闭连接的⽅式通常有两种,分别是 RST 报⽂关闭和 FIN 报⽂关闭。 如果进程异常退出了,内核就会发送 RST 报⽂来关闭,它可以不⾛四次挥⼿流程,是⼀个暴⼒关闭连接的⽅式。 安全关闭连接的⽅式必须通过四次挥⼿,它…

uniap app跳转小程序

微信开放平台申请账号并认证配置APP的相关配 其中安卓的包名可以通过反编译工具查看链接 https://download.csdn.net/download/u010843503/88725345d打开后 其中md5就是签名,复制后把中间空格取消就行。 微信开放平台绑定小程序 绑定后查看微信小程序的原始id也…

win11+vscode+Flutter 开发环境配置

https://blog.csdn.net/Oven_maizi/article/details/126804404 1 vscode插件 安装 安装红框中的两个 2 flutter sdk 安装 dart sdk 包含在flutter sdk 里面,路径:flutter_windows_3.24.1-stable\flutter\bin\cache\dart-sdk 方式1: 通过…

CSS中表示长度的单位有哪些?有什么区别?

CSS中有px、em和rem三个长度单位。px是固定像素,不随页面大小变化;em和rem是相对长度单位,em相对于父元素,rem相对于根元素(html)。 在响应式布局中,rem更常用,因为它只有一个参照物…

Ansible与Docker集成:实现容器化运维自动化

Ansible与Docker集成:实现容器化运维自动化 在现代 DevOps 和云原生环境中,Ansible 和 Docker 是两种非常受欢迎的工具。Ansible 专注于配置管理和任务自动化,而 Docker 则通过容器化技术实现应用的轻量级隔离和部署。将 Ansible 和 Docker …

基于udp的socket网络编程

套接字 网络套接字 原始套接字 unix套接字 windows下SOCKET 为整数。 协议家族 套接字种类 协议 udpServer.cc #pragma warning(disable:4996) #include<iostream> #include<string> #include<cstdlib> #include<WinSock2.h>#pragma comment(li…

mac电脑里面的 磁盘分区,容器,宗卷,宗卷组的理解和使用

在mac电脑里面我们一般都是使用宗卷&#xff0c;他和我们常见的pc机器硬盘的分区是有区别的。 对于物理硬盘来说 不管是分区还是宗卷&#xff0c;他们都是逻辑上面的概念。 分区 mac电脑里面的分区 和 pc电脑中的分区差不多&#xff0c; 他们都是针对的物理硬盘&#xff0c;…

Java 方法的特性详解

目录 一、引言 二、方法的重载 &#xff08;一&#xff09;定义与作用 &#xff08;二&#xff09;判断方法相同的标准 三、可变个数形参的方法 &#xff08;一&#xff09;使用场景 &#xff08;二&#xff09;格式与特点 &#xff08;三&#xff09;代码示例 四、方…

【大模型】llama系列模型基础

前言&#xff1a;llama基于transformer架构&#xff0c;与GPT相似&#xff0c;只用了transformer的解码器部分。本文主要是关于llama&#xff0c;llama2和llama3的结构解读。 目录 1. llama1.1 整体结构1.2 RoPE1.3 SwiGLU 激活函数 2. llama22.2 GQA架构2.3 RLHF 3. llama3参考…

ubuntu20.04(wsl2)测试 arcface 人脸识别(计算特征向量)

1. 参考博客和代码、模型仓库&#xff1a; 1.1. 【C随记】collect2: error: ld returned 1 exit status错误分析与解决 1.2. Visual Studio 2022新建 cmake 工程测试 tensorRT 自带样例 sampleOnnxMNIST 1.3.报错&#xff1a;ModuleNotFoundError: No module named ‘ten…

力扣SQL仅数据库(570-579)

570. 至少有5名直接下属的经理 需求&#xff1a; 编写一个解决方案&#xff0c;找出至少有五个直接下属的经理 数据准备&#xff1a; Create table If Not Exists Employee (id int, name varchar(255), department varchar(255), managerId int) Truncate table Employee i…

Mysql梳理1——数据库概述(上)

笔记来源&#xff1a;【MySQL数据库入门到大牛&#xff0c;mysql安装到优化&#xff0c;百科全书级&#xff0c;全网天花板】 https://www.bilibili.com/video/BV1iq4y1u7vj 目录 11.2 引入 11.2. 1 数据库与数据库管理系统 11.2.2 数据库与数据库管理系统的关系 11.2.…

nnunetv2(一)配置文件和nnUNetv2_convert_MSD_dataset命令

文章目录 setup.pypyproject.tomlconfiguration.pynnUNetv2_convert_MSD_dataset 如有错误&#xff0c;欢迎评论 setup.py 可以使用pip install .命令来安装nnunet v2 pyproject.toml 配置文件 [project] name "nnunetv2" # 项目名称 version "2.5" # …

jmeter中响应时间、TPS、服务器资源图表

插件下载可以参考前面文章&#xff1a;相关插件 一、响应时间图表 jmeter中的聚合报告已经足够显示响应时间&#xff0c;但是不会显示很详细&#xff0c;下面使用监听器中的插件查看&#xff0c; 添加后&#xff0c;可以不用更改任何配置&#xff0c;直接使用默认即可统计响应…

vue3 + ts + element ui plus 添加阿里图标库图标(只添加一个, 并引入)

先创建一个vue文件, 引入svg代码, 这个文件放components里也挺好 ** catalogIcon.vue代码如下: ** <template><svg t"1725419972935" class"icon" viewBox"0 0 1024 1024" version"1.1" xmlns"http://www.w3.org/20…

深度学习--机器学习相关(3)

1.K-近邻算法 KNN 听起来像是某种神经网络的名字&#xff0c;如RNN、CNN 等&#xff0c;其实不然&#xff0c;这是一种经典、简单的分类算法K- 近邻算法(K-Nearest Neighbor,KNN)。与无监督学习讲解的聚类算法不同&#xff0c;KNN 是一个有监督算法。 有监督学习是一种学习算…

多目标应用:四种多目标优化算法(NSGA2、NSPSO、NSDBO、NSCOA)求解柔性作业车间调度问题(FJSP),MATLAB代码

一、柔性作业车间调度问题 柔性作业车间调度问题(Flexible Job Scheduling Problem, FJSP) 的描述如下&#xff1a;n个工件 { J , J 2 , . . , J n } \{J,J_2,..,J_n\} {J,J2​,..,Jn​}要在 m m m 台机器 { M 1 , M 2 , . . , M m } \{M_1,M_2,..,M_m\} {M1​,M2​,..,Mm​} …

div3 970

Problem - D - Codeforces 关键在于如果是环的话&#xff0c;环中的每一个的值都是一样的 #include<bits/stdc.h> #define int long long using namespace std; signed main(){int nn;cin>>nn;while(nn--){int n;cin>>n;int a[n1],i0;while(i<n)cin>…