【Spring】Spring 事务
Spring 事务
文章目录
- Spring 事务
- 1. 简介
- 2. Spring事务管理器
- 3. 基本使用
- 4. 属性剖析
- 5. 声明式事务问题场景
- 5.1 事务不生效
- 5.2 事务不回滚
- 5.3 大事务问题
- 6. 编程式事务
1. 简介
- 编程式事务:指手动编写程序来管理事务,即通过编写代码的方式直接控制事务的提交和回滚。主要优点是灵活性高,可以按照自己的需求来控制事务的粒度、模式等等。但是,一般编写大量的事务控制代码容易出现问题,对代码的可读性和可维护性有一定影响。
- 声明式事务:指使用注解或 XML 配置的方式来控制事务的提交和回滚。
下面除了第6节编程式事务,其他都是指声明式事务。
2. Spring事务管理器
Spring声明式事务对应依赖
spring-tx
:包含声明式事务实现的基本规范(事务管理器规范接口和事务增强等等)spring-jdbc
:包含DataSource
方式事务管理器实现类DataSourceTransactionManager
spring-orm
:包含其他持久层框架的事务管理器实现类例如:Hibernate/Jpa
等
Spring声明式事务对应事务管理器接口:
较常使用的事务管理器是 org.springframework.jdbc.datasource.DataSourceTransactionManager
,将来整合 JDBC方式、JdbcTemplate方式、Mybatis方式的事务实现
DataSourceTransactionManager类中的主要方法:
doBegin()
:开启事务doSuspend()
:挂起事务doResume()
:恢复挂起的事务doCommit()
:提交事务doRollback()
:回滚事务
3. 基本使用
- 添加依赖
<!-- 声明式事务依赖-->
<dependency><groupId>org.springframework</groupId><artifactId>spring-tx</artifactId><version>6.0.6</version>
</dependency>
- 开启事务注解:
@EnableTransactionManagement
- 添加事务管理器到 IoC 容器中
/**
* 装配事务管理实现对象
* @param dataSource
* @return
*/
@Bean
public TransactionManager transactionManager(DataSource dataSource){return new DataSourceTransactionManager(dataSource);
}
- 在类上或方法上使用
@Transactional
- 在类上使用,则会影响到类中的每个方法同时,类级别标记的 @Transactional 注解中设置的事务属性也会延续影响到方法执行时的事务属性。除非在方法上又设置了 @Transactional 注解。对一个方法来说,离它最近的 @Transactional 注解中的事务属性设置生效。
4. 属性剖析
-
timeout
:默认 -1 ,表示永不超时,超时则会事务回滚 -
rollbackFor
:表示遇到属于该异常的类进行事务回滚,默认遇到 RuntimeException 及其子类和 Error 及其子类时才会回滚
,建议设置rollbackFor = Exception.class
或者Throwable.class
表示Exception及其子类
或Throwable
的异常都会触发回滚,同时不影响Error的回滚 -
propagation
:事务的传播行为,默认Propagation.REQUIRED
,一共有七种,一般只使用前两种事务传播行为类型 说明 REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见也是默认的选择。 REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。 SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。 MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。 NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。 NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 REQUIRED
类似的操作 -
isolation
:用于设置事务的隔离级别,Isolation.DEFAULT
,一般不修改 -
readOnly
:默认 false,设置为 true 则只能做读操作,用于数据库针对查询优化,一般不使用
5. 声明式事务问题场景
5.1 事务不生效
- 未开启事务 :未使用开启事务注解
@EnableTransactionManagement
- 未被Spring管理 :被代理类需被Spring管理才能使用 AOP 功能
- 访问权限问题 :只有
public
权限修饰的方法才支持声明式事务 - 方法用
final
或static
修饰 :spring 事务底层用了 jdk 动态代理或者 cglib 生成代理类,这两个关键字将导致重写代理类的该方法 - 多线程调用 :不同线程获取到的数据库连接不一样,从而必然是两个不同的事务
- 表不支持事务 :数据库表引擎是
myisam
或其他不支持事务的引擎 - 方法内调用另一个同类方法:如下,add方法中调用了事务方法
updateStatus()
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public void add(UserModel userModel) {userMapper.insertUser(userModel);updateStatus(userModel);}@Transactionalpublic void updateStatus(UserModel userModel) {doSameThing();}
}
updateStatus()
方法拥有事务的能力是因为 spring aop
生成代理了对象,但这种方式调用了 this 对象的方法,所以 updateStatus 方法不会生成事务。
修改方式:
- 新加一个 Service 将方法中挪到新的 Service 中,通过新 Service 调用
- 在该 Service 中注入自己,再将调用改为
userService.updateStatus(userModel)
- 使用
AopContext.currentProxy()
调用,即改为((UserService)AopContext.currentProxy()).updateStatus(userModel)
,推荐
@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public void add(UserModel userModel) {userMapper.insertUser(userModel);((UserService)AopContext.currentProxy()).updateStatus(userModel)}@Transactionalpublic void updateStatus(UserModel userModel) {doSameThing();}
}
5.2 事务不回滚
- 错误的传播机制 :设置了
propagation = Propagation.NEVER
- try…catch…吞了异常:在 catch 中不抛出任何异常或抛了别的异常 spring 事务也不会回滚
- rollbackFor参数不合理 :当发生了不属于
rollbackFor
定义的异常类及其子类的异常时,事务将不会回滚
5.3 大事务问题
通常情况下,我们会在方法上加 @Transactional
注解,添加事务功能,比如:
@Transactional
public void add(UserModel userModel) throws Exception {query1();query2();query3();roleService.save(userModel);update(userModel);
}
但 @Transactional
注解,如果被加到方法上,有个缺点就是整个方法都包含在事务当中了。上面的这个例子中,在 UserService
类中,其实只有这两行才需要事务,但是这种写法会导致所有的 query()
方法也被包含在同一个事务中。如果 query 方法非常多,调用层级很深,而且有部分查询方法比较耗时的话,会造成整个事务非常耗时,而从造成大事务问题。
6. 编程式事务
5中所提到的问题都是声明式事务的,一般建议少使用声明式事务,但并不是说一定不能用它,如果项目中有些业务逻辑比较简单,而且不经常变动,使用 @Transactional
注解开启事务也无妨,因为它更简单,开发效率更高,但是千万要小心事务失效的问题。大项目更建议使用基于 TransactionTemplate
的编程式事务,即通过手动编写代码实现的事务。
基于 TransactionTemplate
模板的编程式事务的使用 :
- 注入
TransactionTemplate
模板到 IoC 容器中
@Bean
public DataSource dataSource() {DruidDataSource dataSource = new DruidDataSource();dataSource.setUsername(username);dataSource.setPassword(password);dataSource.setUrl(url);dataSource.setDriverClassName(driver);return dataSource;
}@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);
}@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager platformTransactionManager) {return new TransactionTemplate(platformTransactionManager);
}
- 注入到需要使用的类中,并使用如下两个方法之一
execute(TransactionCallback<T> action)有返回值
executeWithoutResult(Consumer<TransactionStatus> action) 无返回值
@Autowize
private TransactionTemplate transactionTemplate;@Transactional
public void add(UserModel userModel) throws Exception {query1();query2();query3();transactionTemplate.executeWithoutResult((status -> {try {roleService.save(userModel);update(userModel);} catch (Exception e) {status.setRollbackOnly();}}));
}
- 异常调用
status.setRollbackOnly()
方法进行回滚
相关文章:

【Spring】Spring 事务
Spring 事务 文章目录 Spring 事务1. 简介2. Spring事务管理器3. 基本使用4. 属性剖析5. 声明式事务问题场景5.1 事务不生效5.2 事务不回滚5.3 大事务问题 6. 编程式事务 1. 简介 编程式事务:指手动编写程序来管理事务,即通过编写代码的方式直接控制事务…...

Ubuntu 虚拟机环境,编译AOSP源码
环境 : VMware虚拟机 Ubuntu 20.04.3 LTS 搭建配置开发环境 sudo apt-get install git-core gnupg flex bison build-essential zip curl zlib1g-dev gcc-multilib g-multilib libc6-dev-i386 libncurses5 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev libgl…...

2023.12.18杂记
今天特地搜了一下国内不错的博客网站,本来想在掘金上写的,但是怕被人喷(,所以还是决定在csdn上写了哈哈哈。 这篇文章主要整理一下我今天写代码时遇到的疑惑以及记录一下思考过程吧。 第一个注意的地方,我们的get查询…...

智能优化算法应用:基于阿基米德优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码
智能优化算法应用:基于阿基米德优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于阿基米德优化算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.阿基米德优化算法4.实验参数设定…...

K8s内容器拓扑图工具
1.背景:随着线上容器越来越多,需要一个可视化的方式展示各个容器之间的拓扑图。 2.需求:轻量级,部署方便。 3.部署 helm repo add groundcover https://helm.groundcover.com/ helm repo update helm install caretta --namespa…...

掌握 Babel:让你的 JavaScript 与时俱进(上)
🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…...

Mysql进阶-InnoDB引擎事务原理及MVCC
事务原理 事务基础 事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系 统提交或撤销操作请求,即这些操作要么同时成功,要么同时失败。 事务的四大特性: 原子性(A…...

「X」Embedding in NLP|神经网络和语言模型 Embedding 向量入门
在「X」Embedding in NLP 进阶系列中,我们介绍了自然语言处理的基础知识——自然语言中的 Token、N-gram 和词袋语言模型。今天,我们将继续和大家一起“修炼”,深入探讨神经网络语言模型,特别是循环神经网络,并简要了解…...

JVM-11-运行时栈帧结构
“栈帧”(Stack Frame)则是用于支持虚拟机进行方法调用和方法执行背后的数据结构,它也是虚拟机运行时数据区中的虚拟机栈(Virtual MachineStack)的栈元素。 栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回…...

【经典LeetCode算法题目专栏分类】【第6期】二分查找系列:x的平方根、有效完全平方数、搜索二位矩阵、寻找旋转排序数组最小值
《博主简介》 小伙伴们好,我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! X的平方根 class Soluti…...
【大麦小米学量化】使用xtquant调用迅投MiniQMT客户端定时操作逆回购,再也不担心忘了赚零花钱了(含完整源代码)
文章目录 前言一、逆回购是什么?1. 什么是逆回购?2. 最低参与金额是多少?3. 逆回购交易是否安全?4. 逆回购交易适合什么类型的客户? 二、讯投XtQuant是什么?1. XtQuant运行依赖环境2. XtQuant运行逻辑 三、…...

php hyperf 读取redis,存储到数据库
背景说明 小白:伟哥,java中的set是无序的,Redis中可以带顺序吗? 伟哥:可以, 不过不叫set了,叫zset。 概述 SortedSet又叫zset,它是Redis提供的特殊数据类型,是一种特殊…...
云原生之深入解析K8S 1.27新特性如何简化状态服务跨集群平滑迁移
一、背景 Kubernetes v1.26 为 StatefulSet 引入了一个新的 Alpha 级别特性,可以控制 Pod 副本的序号。从 Kubernetes v1.27 开始,此特性进级到 Beta 阶段。序数可以从任意非负数开始, 那么该如何使用此功能呢?StatefulSet 序号为…...

鸿蒙OS:打破界限的操作系统新星
导言 鸿蒙OS(HarmonyOS)是华为公司为应对技术封锁而推出的分布式操作系统,其背后蕴含着华为构建全球数字生活愿景的雄心。本文将深入剖析鸿蒙OS的起源、核心特性,并展望其未来在数字生态中的角色。 1. 背景与起源 华为的…...

预测性维护在汽车制造行业中的应用
汽车制造行业是一个高度复杂和精细化的领域,依赖于各种设备来完成生产流程。这些设备包括机械装配线、焊接机器人、喷涂设备、传送带等。然而,这些设备在长时间运行中不可避免地会遇到各种故障,给生产进程带来延误和成本增加。为了应对这一挑…...

分布式链路追踪 —— 基于Dubbo的traceId追踪传递
文章目录 原文链接RpcContext 上下文对象Dubbo 过滤器(Filter)对象基于Dubbo的traceId追踪传递实现 原文链接 RpcContext 上下文对象 在实现 Dubbo 调用之间的链路跟踪之前,先简单了解 RpcContext 上下文对象和 Filter 过滤器对象ÿ…...

【uniapp小程序-上拉加载】
在需要上拉加载的页面的page.json上添加红框框里面的 onReachBottom() {if(this.commentCurrent<this.commentTotal){this.commentCurrent 1; this.commentList();this.status loading;}else{this.status ;} }, methods:{commentList(){let params {courseid:this.cour…...
ubuntu添加路由
ip route show 查看当前路由表 sudo ip route add /mask via 添加一条路由 目标ip 1.1.1.1/100 下一跳 2.2.2.2 sudo ip route add 1.1.1.1/100 via 2.2.2.2 dev ens160 proto static metric 100这是一条Linux命令,用于添加一个静态路由。具体含义如下࿱…...

python图像二值化处理
目录 1、双峰法 2、P参数法 3、迭代法 4、OTSU法 图像的二值化处理是将图像上的像素点的灰度值设置为0或255,也就是将整个图像呈现出明显的只有黑和白的视觉效果。二值化是图像分割的一种最简单的方法,可以把灰度图像转换成二值图像。具体实现是将大…...

4.配置系统时钟思路及方法
前言: 比起之前用过的三星的猎户座4412芯片,STM32F4的系统时钟可以说是小巫见大巫,首先我们需要清晰时钟产生的原理:几乎大多数的芯片都是由晶振产生一个比较低频的频率,然后通过若干个PLL得到单片机能承受的频率&…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
Caliper 配置文件解析:fisco-bcos.json
config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...
「Java基本语法」变量的使用
变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...

C++中vector类型的介绍和使用
文章目录 一、vector 类型的简介1.1 基本介绍1.2 常见用法示例1.3 常见成员函数简表 二、vector 数据的插入2.1 push_back() —— 在尾部插入一个元素2.2 emplace_back() —— 在尾部“就地”构造对象2.3 insert() —— 在任意位置插入一个或多个元素2.4 emplace() —— 在任意…...