Spring事务-两种开启事务管理的方式:基于注解的声明式事务管理、基于编程式的事务管理
Spring事务-两种开启事务管理的方式
- 1、前期准备
- 2、基于注解的声明式事务管理
- 3、基于编程式的事务管理
- 4、声明式事务失效的情况
例子:假设有一个银行转账的业务,其中涉及到从一个账户转钱到另一个账户。在这个业务中,我们需要保证要么两个账户都成功更新,要么都不更新,以避免出现数据不一致的情况。以下是基于注解的声明式事务管理和编程式事务管理的示例:
1、前期准备
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId><version>2.5.4</version></dependency>
首先是实体类 Account:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;@Entity
@TableName("account")
public class Account {@Idprivate Long id; //银行账户的唯一标识符private String accountNumber; //银行账户的账号,用于唯一标识一个账户private double balance; //银行账户的余额,表示账户当前的可用资金数量// getters and setters
}


然后是 AccountRepository:
import org.springframework.data.jpa.repository.JpaRepository;
@Mapper
public interface AccountRepository extends JpaRepository<Account, Long> {Account findByAccountNumber(String accountNumber);
}
然后是控制器类 BankController:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;@RestController
public class BankController {@Autowiredprivate BankService bankService;@PostMapping("/transfer")public String transfer(@RequestBody TransferRequest request) {bankService.transfer(request.getFromAccount(), request.getToAccount(), request.getAmount());return "Transfer successful";}
}
接下来是请求体类 TransferRequest:
public class TransferRequest {private String fromAccount;private String toAccount;private double amount;// getters and setters
}
2、基于注解的声明式事务管理
这种方式使用注解来定义事务,通过在需要进行事务管理的方法上添加相应的注解来标识事务的边界和属性。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class BankService {@Autowiredprivate AccountRepository accountRepository;@Transactionalpublic void transfer(String fromAccount, String toAccount, double amount) {Account from = accountRepository.findByAccountNumber(fromAccount);Account to = accountRepository.findByAccountNumber(toAccount);from.setBalance(from.getBalance() - amount);to.setBalance(to.getBalance() + amount);accountRepository.save(from);int i = 1/0;accountRepository.save(to);}
}

报错,事务回滚


在上面的示例中,@Transactional注解被用于标记transfer方法。这表示transfer方法将被Spring框架管理事务。如果该方法执行过程中发生异常,Spring会回滚所有的数据库操作,以保证数据的一致性。
3、基于编程式的事务管理
编程式事务管理是一种通过编程方式手动控制事务的管理过程。与声明式事务管理相比,它不依赖于特定的注解或配置,而是在代码中显式地编写事务管理逻辑。在编程式事务管理中,开发人员需要手动管理事务的开始、提交、回滚等过程。
编程式事务管理的主要原理包括以下几个方面:
-
事务定义(Transaction Definition): 在编程式事务管理中,首先需要定义事务的属性,包括事务的传播行为、隔离级别、超时时间等。这些定义将决定事务的行为。
-
事务管理器(Transaction Manager): 事务管理器负责实际管理事务,包括事务的开始、提交、回滚等操作。在编程式事务管理中,通常需要手动获取事务管理器,并调用其方法来管理事务。
-
事务的控制: 在编程式事务管理中,开发人员需要显式地控制事务的开始、提交、回滚等过程。这通常通过调用事务管理器的方法来实现,如获取事务、提交事务、回滚事务等。
-
异常处理: 在事务管理过程中,可能会出现各种异常情况。开发人员需要适当地处理这些异常,例如在捕获到异常时执行事务的回滚操作,以保证数据的一致性。
-
事务边界: 在编程式事务管理中,需要明确定义事务的边界,即事务开始和结束的位置。通常事务的边界由业务逻辑决定,在业务逻辑的开始处开启事务,在结束处提交或回滚事务。
首先需要定义事务管理器 Bean: 在 Spring Boot 应用程序的配置类中,使用 @Bean 注解定义一个名为 transactionManager 的 DataSourceTransactionManager Bean。确保该 Bean 使用了正确的数据源。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import javax.sql.DataSource;@Configuration
public class TransactionConfig {@Beanpublic DataSourceTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}
service
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class BankService {@Autowiredprivate AccountRepository accountRepository;@Autowiredprivate DataSourceTransactionManager transactionManager;public void transfer(String fromAccount, String toAccount, double amount) {DefaultTransactionDefinition def = new DefaultTransactionDefinition();def.setName("transaction-1");def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);TransactionStatus status = transactionManager.getTransaction(def);try {Account from = accountRepository.findByAccountNumber(fromAccount);Account to = accountRepository.findByAccountNumber(toAccount);from.setBalance(from.getBalance() - amount);to.setBalance(to.getBalance() + amount);accountRepository.save(from);accountRepository.save(to);transactionManager.commit(status);} catch (Exception e) {transactionManager.rollback(status);throw e;}}
}


在这个示例中,我们直接使用了DataSourceTransactionManager来手动管理事务。我们首先定义了一个事务的定义(DefaultTransactionDefinition),然后使用该定义来开启一个事务。如果执行过程中发生异常,我们手动回滚事务;如果一切正常,则手动提交事务。
4、声明式事务失效的情况
- @Transactional 应用在非 public 修饰的方法上
- @Transactional 注解属性 propagation 设置错误
- @Transactional 注解属性 rollbackFor 设置错误
- 同一个类中方法调用,导致@Transactional失效
- 异常被catch捕获导致@Transactional失效
- 数据库引擎不支持事务
笔者有空再针对这几种情况进行说明
相关文章:
Spring事务-两种开启事务管理的方式:基于注解的声明式事务管理、基于编程式的事务管理
Spring事务-两种开启事务管理的方式 1、前期准备2、基于注解的声明式事务管理3、基于编程式的事务管理4、声明式事务失效的情况 例子:假设有一个银行转账的业务,其中涉及到从一个账户转钱到另一个账户。在这个业务中,我们需要保证要么两个账户…...
OC 技术 苹果内购
一直觉得自己写的不是技术,而是情怀,一个个的教程是自己这一路走来的痕迹。靠专业技能的成功是最具可复制性的,希望我的这条路能让你们少走弯路,希望我能帮你们抹去知识的蒙尘,希望我能帮你们理清知识的脉络࿰…...
云原生周刊:Kubernetes v1.30 一瞥 | 2024.3.25
开源项目推荐 Retina Retina 是一个与云无关的开源 Kubernetes 网络可观测平台,它提供了一个用于监控应用程序运行状况、网络运行状况和安全性的集中中心。它为集群网络管理员、集群安全管理员和 DevOps 工程师提供可操作的见解,帮助他们了解 DevOps、…...
2016年认证杯SPSSPRO杯数学建模D题(第一阶段)NBA是否有必要设立四分线解题全过程文档及程序
2016年认证杯SPSSPRO杯数学建模 D题 NBA是否有必要设立四分线 原题再现 NBA 联盟从 1946 年成立到今天,一路上经历过无数次规则上的变迁。有顺应民意、皆大欢喜的,比如 1973 年在技术统计中增加了抢断和盖帽数据;有应运而生、力挽狂澜的&am…...
EdgeGallery开发指南
API接口 简介 EdgeGallery支持第三方业务系统通过北向接口网关调用EdgeGallery的业务接口。调用流程如下图所示(融合前端edgegallery-fe包含融合前端界面以及北向接口网关功能,通过浏览器访问时打开的是融合前端的界面,通过IP:Port/urlPref…...
ubuntu arm qt 读取execl xls表格数据
一,ubuntu linux pc编译读取xls的库 1,安装libxls(读取xls文件 电脑版) 确保你已经安装了基本的编译工具,如gcc和make。如果没有安装,可以使用以下命令安装: sudo apt-update sudo apt-get install build-essentia…...
STM32 使用gcc编译介绍
文章目录 前言1. keil5下的默认编译工具链用的是哪个2. Arm编译工具链和GCC编译工具链有什么区别吗?3. Gcc交叉编译工具链的命名规范4. 怎么下载gcc-arm编译工具链参考资料 前言 我们在STM32上进行开发时,一般都是基于Keil5进行编译下载,Kei…...
FPGA之组合逻辑与时序逻辑
数字逻辑电路根据逻辑功能的不同,可以分成两大类:组合逻辑电路和时序逻辑电路,这两种电路结构是FPGA编程常用到的,掌握这两种电路结构是学习FPGA的基本要求。 1.组合逻辑电路 组合逻辑电路概念:任意时刻的输出仅仅取决…...
git clone没有权限的解决方法
一般情况 git clone时没有权限,一般是因为在代码库平台上没有配置本地电脑的id_rsa.pub 只要配置上,一般就可以正常下载了。 非一般情况 但是也有即使配置了id_rsa.pub后,仍然无法clone代码的情况。如下 原因 这种情况是因为ssh客户端…...
Redis 的内存回收策略
Redis的内存回收策略用于处理过期数据和内存溢出情况,确保系统稳定性和性能。作为一个高性能的键值存储系统,它通过内存回收策略来维护内存的高效使用 主要包括过期删除策略和内存淘汰策略。 过期删除策略: Redis的过期删除策略是通过设置…...
小程序富文本图片宽度自适应
解决这个问题 创建一个util.js文件,图片的最大宽度设置为100%就行了 function formatRichText(html) {let newContent html.replace(/\<img/gi, <img style"max-width:100%;height:auto;display:block;");return newContent; }module.exports {formatRichT…...
安装redis时候修改过的配置文件
只要是石头,到哪里都不会发光的 bind 绑定主机某个网卡对应的IP地址,如果某个主机有两个网卡A和B,那么绑定了A,通过B连接就会无法访问protected-mode 保护模式 Yes为只能本地访问port 启动的端口号pidfile pid存放的位置ÿ…...
Stable Diffusion 本地部署教程
Stable Diffusion是一种用于构建和部署机器学习模型的开源工具。以下是在本地环境中部署 Stable Diffusion 的基本步骤: 步骤 1: 准备环境 确保你的系统中已经安装了以下软件和工具: Python(建议使用 Python 3.x)pip(Python 包管理工具)Docker(可选,用于容器化部署)…...
sql如何增加数据
在MySQL中增加数据主要是通过INSERT INTO SQL语句来实现的。以下是对插入语句的详细介绍以及举例说明: 1、插入语句的基本格式: 1INSERT INTO table_name (column1, column2, ..., columnN) 2VALUES (value1, value2, ..., valueN); table_name&#x…...
智慧交通(代码实现案例)
1.项目简介 目标: 了解智慧交通项目的架构知道智慧交通项目中的模块能够完成智慧交通项目的环境搭建 该项目是智慧交通项目,通过该项目掌握计算机视觉的方法在交通领域的相关应用,包括车道线检测的方法,多目标车辆追踪及流量统计方法&#…...
LeetCode 面试经典150题 205.同构字符串
题目: 给定两个字符串 s 和 t ,判断它们是否是同构的。 如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的。 每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字…...
存内计算:释放潜能的黑科技
什么是存内计算? 存内计算技术是一种新型的计算架构,它将存储器和计算单元融合在一起,以实现高效的数据处理。存内计算技术的优势在于能够消除数据搬运的延迟和功耗,从而提高计算效率和能效比。目前,存内计算技术正处…...
CentOS Stream 8系统配置阿里云YUM源
Linux运维工具-ywtool 目录 一.系统环境二.修改yum文件2.1 CentOS-Stream-AppStream.repo2.2 CentOS-Stream-BaseOS.repo2.3 CentOS-Stream-Extras.repo 三.只有一个配置文件四.其他知识4.1 如果想要启用其他源,修改文件配置:enabled14.2 国内源链接 一.系统环境 CentOS Strea…...
MySQL Explain 优化参数详细介绍
Explain 是什么? Explain命令用于分析SQL查询的执行计划,帮助优化查询语句和索引选择。 Explain是MySQL提供的一个非常有用的工具,它能够帮助数据库管理员和开发者理解SQL查询是如何被数据库执行的。通过在SELECT语句前加上EXPLAIN关键字,…...
代码随想录Day58:每日温度、下一个更大元素 I
每日温度 class Solution { public:vector<int> dailyTemperatures(vector<int>& temperatures) {stack<int> st;vector<int> result(temperatures.size(), 0);for(int i 0; i < temperatures.size(); i){while(!st.empty() && tempe…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
土建施工员考试:建筑施工技术重点知识有哪些?
《管理实务》是土建施工员考试中侧重实操应用与管理能力的科目,核心考查施工组织、质量安全、进度成本等现场管理要点。以下是结合考试大纲与高频考点整理的重点内容,附学习方向和应试技巧: 一、施工组织与进度管理 核心目标: 规…...
华为OD机考- 简单的自动曝光/平均像素
import java.util.Arrays; import java.util.Scanner;public class DemoTest4 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint[] arr Array…...
Git 切换到旧提交,同时保证当前修改不丢失
在 Git 中,可以通过以下几种方式切换到之前的提交,同时保留当前的修改 1. 使用 git checkout 创建临时分离头指针(推荐用于查看代码) git checkout <commit-hash>这会让你进入"分离头指针"状态,你可…...
《开篇:课程目录》
大家好!我是一名.NET技术开发者,长期以来积累了比较多的项目实战经验,现在把它分享给大家,希望能够帮助到大家,同时为.NET社区提供一份力量,让更多的开发者参与进来。 要讲解的课程如下: 《介绍…...
