Spring 事务及管理方式
Spring 事务管理是 Spring 框架的核心功能之一,它为开发者提供了一种方便、灵活且强大的方式来管理数据库事务。
1、事务的基本概念
事务是一组不可分割的操作序列,这些操作要么全部成功执行,要么全部失败回滚,以确保数据的一致性和完整性。事务具有四个特性,即 ACID 特性:
-
原子性(Atomicity):事务中的所有操作要么全部执行成功,要么全部失败回滚。
-
一致性(Consistency):事务执行前后,数据库的状态必须保持一致。
-
隔离性(Isolation):多个事务并发执行时,一个事务的执行不能被其他事务干扰。
-
持久性(Durability):事务一旦提交,其对数据库的更改将永久保存。
2、事务的传播行为
事务的传播行为定义了在嵌套事务场景下,事务如何传播。Spring 定义了 7 种事务传播行为:
-
PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
-
PROPAGATION_SUPPORTS:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
-
PROPAGATION_MANDATORY:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
-
PROPAGATION_REQUIRES_NEW:创建一个新的事务,如果当前存在事务,则将当前事务挂起。
-
PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,则将当前事务挂起。
-
PROPAGATION_NEVER:以非事务方式执行操作,如果当前存在事务,则抛出异常。
-
PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则创建一个新的事务。
使用 @Transactional 注解指定传播行为的示例:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Transactional(propagation = Propagation.REQUIRES_NEW)public void transferMoney() {// 执行数据库操作}
}
3、事务的隔离级别
事务的隔离级别定义了一个事务对其他事务的可见性。Spring 支持 4 种事务隔离级别:
-
ISOLATION_DEFAULT:使用数据库默认的隔离级别。
-
ISOLATION_READ_UNCOMMITTED:允许读取未提交的数据,可能会导致脏读、不可重复读和幻读。
-
ISOLATION_READ_COMMITTED:只允许读取已提交的数据,可以避免脏读,但可能会导致不可重复读和幻读。
-
ISOLATION_REPEATABLE_READ:确保在同一个事务中多次读取同一数据的结果是一致的,可以避免脏读和不可重复读,但可能会导致幻读。
-
ISOLATION_SERIALIZABLE:最高的隔离级别,确保事务串行执行,可以避免脏读、不可重复读和幻读,但会影响并发性能。
使用 @Transactional 注解指定隔离级别的示例:
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Transactional(isolation = Isolation.READ_COMMITTED)public void transferMoney() {// 执行数据库操作}
}
4、Spring 事务管理的实现方式
Spring 提供了两种事务管理方式:编程式事务管理和声明式事务管理。
4.1 编程式事务管理
编程式事务管理需要在代码中显式地管理事务的开始、提交和回滚。Spring 提供了 TransactionTemplate 或 PlatformTransactionManager 来实现编程式事务管理。
使用 TransactionTemplate 的示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;@Service
public class UserService {@Autowiredprivate TransactionTemplate transactionTemplate;public void transferMoney() {transactionTemplate.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus status) {try {// 执行数据库操作// 例如:从账户 A 转账到账户 B} catch (Exception e) {status.setRollbackOnly();}}});}
}
使用 PlatformTransactionManager的示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;@Service
public class UserService {@Autowiredprivate PlatformTransactionManager transactionManager;public void addUser() {TransactionDefinition def = new DefaultTransactionDefinition();TransactionStatus status = transactionManager.getTransaction(def);try {// 业务逻辑代码transactionManager.commit(status);} catch (Exception e) {transactionManager.rollback(status);}}
}
解释
-
PlatformTransactionManager:Spring 提供的事务管理器接口,用于管理事务的提交、回滚等操作。 -
TransactionDefinition:定义事务的属性,如隔离级别、传播行为等。 -
TransactionStatus:表示当前事务的状态,通过transactionManager.getTransaction(def)方法获取。 -
手动提交和回滚:在代码中手动调用
transactionManager.commit(status)提交事务,调用transactionManager.rollback(status)回滚事务。
优缺点
-
优点:
-
对事务的控制非常精细,可以根据业务逻辑在代码的任何位置灵活地开启、提交或回滚事务。
-
适用于复杂的事务处理场景,例如需要根据不同的业务条件动态决定是否提交或回滚事务。
-
-
缺点:
-
代码中会包含大量的事务管理代码,导致业务逻辑和事务管理逻辑耦合度高,增加了代码的复杂度和维护难度。
-
当业务逻辑发生变化时,可能需要同时修改事务管理代码,不符合开闭原则。
-
适用场景
-
事务逻辑复杂,需要根据业务条件动态控制事务的提交和回滚。
-
对事务管理有特殊需求,例如需要在事务中执行一些非数据库操作,并且要保证这些操作与数据库操作的原子性。
4.2 声明式事务管理
声明式事务管理是通过 AOP(面向切面编程)实现的,它允许开发者通过配置的方式来定义事务的边界,而不需要在代码中显式地管理事务。声明式事务管理有两种配置方式:基于 XML 配置和基于注解配置。
@Transactional 注解默认的事务隔离级别是 ISOLATION_DEFAULT
@Transactional 注解默认的事务传播行为是 PROPAGATION_REQUIRED
基于注解配置的示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Autowiredprivate UserDao userDao;@Transactionalpublic void transferMoney() {// 执行数据库操作// 例如:从账户 A 转账到账户 B}
}
解释
-
@Transactional注解:在方法上添加@Transactional注解,Spring 会自动管理该方法的事务。如果方法执行过程中抛出异常,Spring 会自动回滚事务。
在配置类中开启事务注解支持:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;import javax.sql.DataSource;@Configuration
@EnableTransactionManagement
public class AppConfig {@Autowiredprivate DataSource dataSource;@Beanpublic PlatformTransactionManager transactionManager() {return new DataSourceTransactionManager(dataSource);}
}
优缺点
-
优点:
-
事务管理代码与业务逻辑分离,降低了代码的耦合度,使业务代码更加简洁、清晰,易于维护。
-
通过配置的方式定义事务,提高了开发效率,减少了重复代码。
-
-
缺点:
-
事务的控制粒度相对较粗,不够灵活。例如,无法在方法内部的某个具体位置精确控制事务的提交和回滚。
-
由于是基于 AOP 实现的,可能会带来一定的性能开销。
-
适用场景
-
事务逻辑相对简单,且事务边界比较固定的场景。
-
大多数业务方法都需要相同的事务管理策略,通过统一的注解配置可以提高开发效率。
注意事项:
1. 注意 @Transactional 注解位置
该注解可以用在方法上,此时仅对该方法生效。要确保该方法是 public 的,因为 Spring AOP 基于代理模式,默认情况下,只有 public 方法才会被代理增强。
若将注解放在类上,意味着该类中的所有 public 方法都会启用事务管理。不过,要注意如果类中有部分方法不需要事务,这种方式可能会带来不必要的事务开销。
2.异常处理与回滚规则
默认回滚规则:@Transactional 默认只对 RuntimeException 及其子类和 Error 进行回滚。如果业务代码中抛出的是受检异常(如 IOException),默认情况下事务不会回滚。
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;@Service
public class UserService {@Transactionalpublic void saveUser() throws IOException {// 业务逻辑throw new IOException("文件操作异常"); // 默认不回滚}
}
自定义回滚规则:可通过 rollbackFor 和 noRollbackFor 属性来指定需要回滚和不需要回滚的异常类型。
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;@Service
public class UserService {@Transactional(rollbackFor = {IOException.class})public void saveUser() throws IOException {// 业务逻辑throw new IOException("文件操作异常"); // 会回滚}
}
3. 事务传播行为和隔离级别
合理选择传播行为:传播行为定义了事务方法如何与当前事务进行交互,有 REQUIRED、SUPPORTS、MANDATORY 等多种传播行为。例如,REQUIRED 是最常用的传播行为,若当前存在事务则加入,不存在则创建新事务;而 SUPPORTS 表示若当前存在事务则加入,不存在则以非事务方式执行。要根据业务需求合理选择,避免不必要的事务嵌套。
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Transactional(propagation = Propagation.REQUIRED)public void saveUser() {// 业务逻辑}
}
隔离级别定义了一个事务对其他事务的可见性,有 READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ 和 SERIALIZABLE 等。过高的隔离级别会增加事务的并发控制开销,要根据业务需求选择合适的隔离级别,如大多数场景使用 READ_COMMITTED 即可。
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Transactional(isolation = Isolation.READ_COMMITTED)public void saveUser() {// 业务逻辑}
}
4. 代理机制
内部方法调用问题
同一类内方法调用:Spring AOP 基于代理模式,当在同一个类的一个无事务方法中调用有 @Transactional 注解的方法时,事务不会生效。因为这种调用没有经过代理对象,而是直接调用目标对象的方法。
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {public void nonTransactionalMethod() {this.transactionalMethod(); // 事务不生效}@Transactionalpublic void transactionalMethod() {// 业务逻辑}
}
可以通过注入自身代理对象来解决,或者将有事务的方法提取到另一个服务类中。
5. 数据源和事务管理器配置
确保数据源与事务管理器匹配:要保证数据源和事务管理器的配置正确且相互匹配。如果使用多个数据源,需要为每个数据源配置相应的事务管理器,并在 @Transactional 注解中指定使用的事务管理器。
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Transactional("transactionManager2")public void saveUser() {// 业务逻辑}
}
6. 缩小事务范围,减少事务持有时间:尽量将不需要事务的操作放在事务之外执行,缩小事务的范围,减少事务持有锁的时间,从而提高并发性能。例如,先进行查询操作,再将需要事务的更新操作放在事务方法中。
4.3 两种方式的对比
| 编程式事务管理 | 声明式事务管理 | |
|---|---|---|
| 代码耦合度 | 高,事务管理代码与业务逻辑代码紧密耦合 | 低,事务管理代码与业务逻辑代码分离 |
| 灵活性 | 高,可以在代码中根据具体情况灵活控制事务的开始、提交和回滚 | 相对较低,主要通过注解配置事务属性 |
| 可维护性 | 低,事务管理代码分散在业务逻辑代码中,维护困难 | 高,事务管理代码集中在注解中,易于维护 |
| 适用场景 | 适用于事务管理逻辑复杂,需要根据具体情况灵活控制事务的场景 | 适用于大多数业务场景,特别是事务管理逻辑相对简单的场景 |
综上所属,编程式事务管理适合复杂的事务处理场景,而声明式事务管理则更适合事务逻辑相对简单、需要提高开发效率和降低代码耦合度的场景。在实际开发中,可以根据具体需求选择合适的事务管理方式。
相关文章:
Spring 事务及管理方式
Spring 事务管理是 Spring 框架的核心功能之一,它为开发者提供了一种方便、灵活且强大的方式来管理数据库事务。 1、事务的基本概念 事务是一组不可分割的操作序列,这些操作要么全部成功执行,要么全部失败回滚,以确保数据的一致…...
GESP2024年9月认证C++七级( 第三部分编程题(1)小杨寻宝)
参考程序: #include <bits/stdc.h> using namespace std; const int N 1e510; vector<int> g[N]; // 图的邻接表 int col[N], dep[N], has[N];// 深度优先遍历,计算每个节点的深度 void dfs(int x, int fa) {dep[x] dep[fa] 1; // 计算…...
Pandas数据填充(fill)中的那些坑:避免机器学习中的数据泄露
1. 问题背景 在处理时间序列数据时,经常会遇到缺失值需要填充。Pandas提供了ffill(forward fill)和bfill(backward fill)两种填充方式,但使用不当可能会导致数据泄露,特别是在进行机器学习预测时。 2. 填充方式解析 2.1 基本概念 ffill(forward fill): 用前面的值填充后面的…...
ubuntu 安装vnc之后,本地黑屏,vnc正常
ubuntu 安装vnc之后,本地黑屏,vnc正常 在Ubuntu系统中安装VNC服务器(如TightVNC或RealVNC)后,如果遇到连接时本地屏幕变黑的情况,可能是由于几种不同的配置或兼容性问题。以下是一些解决步骤,可以帮助你解决这个问题&…...
解锁电商数据宝藏:淘宝商品详情API实战指南
在电商蓬勃发展的今天,数据已成为驱动业务增长的核心引擎。对于商家、开发者以及数据分析师而言,获取精准、实时的商品数据至关重要。而淘宝,作为国内最大的电商平台,其海量商品数据更是蕴含着巨大的价值。 本文将带你深入探索淘…...
webshell通信流量分析
环境安装 Apatche2 php sudo apt install apache2 -y sudo apt install php libapache2-mod-php php-mysql -y echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php sudo ufw allow Apache Full 如果成功访问info.php,则环境安…...
在 rtthread中,rt_list_entry (rt_container_of) 已知结构体成员的地址,反推出结构体的首地址
rt_list_entry (rt_container_of)宏定义: /*** rt_container_of - return the start address of struct type, while ptr is the* member of struct type.*/ #define rt_container_of(ptr, type, member) \((type *)((char *)(ptr) - (unsigned long)(&((type *…...
趣味魔法项目 LinuxPDF —— 在 PDF 中启动一个 Linux 操作系统
最近,一位开源爱好者开发了一个LinuxPDF 项目(ading2210/linuxpdf: Linux running inside a PDF file via a RISC-V emulator),它的核心功能是在一个 PDF 文件中启动并运行 Linux 操作系统。它通过巧妙地使用 PDF 文件格式中的 Ja…...
DeepSeek教unity------MessagePack-03
数据契约兼容性 你可以使用 [DataContract] 注解代替 [MessagePackObject]。如果类型用 DataContract 进行注解,可以使用 [DataMember] 注解代替 [Key],并使用 [IgnoreDataMember] 代替 [IgnoreMember]。 然后,[DataMember(Order int)] 的…...
【Linux】Socket编程—TCP
🔥 个人主页:大耳朵土土垚 🔥 所属专栏:Linux系统编程 这里将会不定期更新有关Linux的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉 文章目…...
新数据结构(9)——Java异常体系
异常的种类 程序本身通常无法主动捕获并处理错误(Error),因为这些错误通常表示系统级的严重问题,但程序可以捕获并处理异常(Excrption),而Error则被视为一种程序无法或不应尝试恢复的异常类型。…...
一种 SQL Server 数据库恢复方案:解密、恢复并导出 MDF/NDF/BAK文件
方案特色 本方案可以轻松恢复和导出SQL数据库:MDF、NDF 和 BAK 文件。 恢复和导出SQL数据库:主(MDF),辅助(NDF)和备份(BAK)文件分析 SQL Server LOG 数据库事务日志将 …...
NixHomepage - 简单的个人网站
💻 NixHomepage - 简单的个人网站 推荐下个人的开源项目,演示网站,项目链接 https://github.com/nixgnauhcuy/NixHomepage,喜欢的话可以为我的项目点个 Star~ 📷 预览 ⚙️ 功能特性 多平台适配 明亮/暗黑模式切换 W…...
HCIA项目实践---OSPF的知识和原理总结
9.5 OSPF 9.5.1 从哪些角度评判一个动态路由协议的好坏? (1)选路佳(是否会出环) OSPF 协议采用链路状态算法,通过收集网络拓扑信息来计算最短路径,从根本上避免了路由环路的产生。 (…...
Calico网络组件本地部署支持IPv6(Kubernetes)
知其然 问题背景 因项目现场的网络正逐步从IPv4向IPv6迁移,这几年现场服务器基本上都配置了双栈;但随着IPv6铺开,出现了很多纯IPv6的服务器,并且要求通信优先使用IPv6。 在项目建设之初,其实就考虑了上述情况&#…...
【广州大学主办,发表有保障 | IEEE出版,稳定EI检索,往届见刊后快至1个月检索】第二届电气技术与自动化工程国际学术会议 (ETAE 2025)
第二届电气技术与自动化工程国际学术会议 (ETAE 2025) The 2nd International Conference on Electrical Technology and Automation Engineering 大会官网:http://www.icetae.com/【更多详情】 会议时间:2025年4月25-27日 会议地点:…...
Python项目31:待办事项列表应用1.0(命令行界面+Json+类+初学者必做)
------------★Python练手项目源码★------------ Python项目27:用Tkinter写日志管理系统(中下等难度) Python项目26:设计学生成绩管理系统(简易版) Python项目25:带滚动效果的商场抽奖系统&…...
Redis 01 02章——入门概述与安装配置
一、入门概述 (1)是什么 Redis:REmote Dictionary Server(远程字典服务器)官网解释:Remote Dictionary Server(远程字典服务)是完全开源的,使用ANSIC语言编写遵守BSD协议,是一个高…...
Large Language Model Distilling Medication Recommendation Model
摘要:药物推荐是智能医疗系统的一个重要方面,因为它涉及根据患者的特定健康需求开具最合适的药物。不幸的是,目前使用的许多复杂模型往往忽视医疗数据的细微语义,而仅仅严重依赖于标识信息。此外,这些模型在处理首次就…...
2025最新版Node.js下载安装~保姆级教程
1. node中文官网地址:http://nodejs.cn/download/ 2.打开node官网下载压缩包: 根据操作系统不同选择不同版本(win7系统建议安装v12.x) 我这里选择最新版win 64位 3.安装node ①点击对话框中的“Next”,勾选同意后点…...
deepseek:三个月备考高级系统架构师
一、备考总体规划(2025年2月11日 - 2025年5月) 1. 第一阶段:基础夯实(2025年2月11日 - 2025年3月10日) 目标:快速掌握系统架构师考试的核心知识点。 重点内容: 计算机组成原理、操作系统、数据…...
springboot如何将lib和jar分离
遇到一个问题,就是每次maven package或者maven install后target中的jar很大,少的50几MB,大的100多兆 优化前: 优化后: 优化前 优化后压缩率77.2MB4.65MB93% 具体方案: pom.xml中 <build><…...
解锁建造者模式:Java 编程中的对象构建秘籍
系列文章目录 后续补充~~~~ 文章目录 一、引言二、建造者模式原理剖析2.1 定义与概念2.2 模式结构与角色2.2.1 产品(Product)2.2.2 建造者(Builder)2.2.3 具体建造者(ConcreteBuilder)2.2.4 指挥者(Director)2.3 工作流程与交互机制三、建造者模式在 Java 中的优势3.1 …...
RocketMQ和Kafka如何实现顺序写入和顺序消费?
0 前言 先说明kafka,顺序写入和消费是Kafka的重要特性,但需要正确的配置和使用方式才能保证。本文需要解释清楚Kafka如何通过分区来实现顺序性,以及生产者和消费者应该如何配合。 首先,顺序写入。Kafka的消息是按分区追加写入…...
Electron 全面解析:跨平台桌面应用开发指南
引言 在当今多平台并存的数字时代,如何高效开发跨平台桌面应用成为开发者面临的重要挑战。Electron作为GitHub开源的跨平台框架,凭借其独特的Web技术融合能力,已成为构建桌面应用的热门选择。本文将深入探讨Electron的核心原理、开发实践及未…...
Node.js技术原理分析系列——Node.js调试能力分析
本文由体验技术团队屈金雄原创。 Node.js 是一个开源的、跨平台的 JavaScript 运行时环境,它允许开发者在服务器端运行 JavaScript 代码。Node.js 是基于 Chrome V8引擎构建的,专为高性能、高并发的网络应用而设计,广泛应用于构建服务器端应…...
从技术债务到架构升级,滴滴国际化外卖的变革
背 景 商家营销简述 在外卖平台的运营中,我们致力于通过灵活的补贴策略激励商家,与商家共同打造良好的合作关系,也会提供多样化的营销活动,帮助商家吸引更多用户下单。通过这些活动,不仅能够提高商家的销量,…...
DeepSeek教unity------MessagePack-05
动态反序列化 当调用 MessagePackSerializer.Deserialize<object> 或 MessagePackSerializer.Deserialize<dynamic> 时,二进制数据中存在的任何值都将被转换为基本值,即 bool、char、sbyte、byte、short、int、long、ushort、uint、ulong、…...
SQL Query美化
推荐一个可以美化Query的网站! 名称:SQL formatter | Online free SQL Beautifier 地址:https://sqlformatter.org/# 在处理 SQL 查询语句时,可读性是至关重要的。 杂乱无章的 SQL代码不仅难以理解,还会给后续的维…...
探索RDMA技术:从基础到实践
1. 引言 在当今的高性能计算(HPC)和数据中心领域,数据传输的效率和速度至关重要。RDMA(Remote Direct Memory Access,远程直接内存访问)技术作为一种高效的网络通信机制,能够显著减少数据传输的延迟和CPU负载。本文将从基础到实践,详细介绍RDMA技术及其编程模型,帮助…...
