Springboot @Transactional使用时需注意的几个问题
一、事务的隔离级别
在Springboot应用中,如果我们想实现方法一旦执行有异常产生,就触发事务回滚,可以在方法上面添加@Transactional注解。如果应用采用mysql数据库,虽然mysql本身也有事务隔离机制,但在Sping+数据库的应用中,会以Spring事务为准。mysql定义的事务隔离级别为可重复读,在使用 Spring Boot 和 MySQL 的组合时,如果你不特别指定隔离级别,那么实际使用的将是 MySQL 的默认值 REPEATABLE READ。如果在一些特定场景中不想使用可重复读,可通过@Transactional注解的isolation属性来指定。isolation支持的选项有:
- ISOLATION_DEFAULT:使用后端数据库默认的隔离级别。
- ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、不可重复读或幻读。
- ISOLATION_READ_COMMITTED:允许读取已经提交的数据,可以防止脏读,但可能会出现不可重复读或幻读。
- ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果是一致的,除非数据是被当前事务本身所修改,可以防止脏读和不可重复读,但幻读仍可能发生。
- ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从 ACID 的隔离级别,所有的事务依次逐个执行,可以防止脏读、不可重复读以及幻读。
使用示例:
@Transactional(isolation = Isolation.READ_COMMITTED)
public void performTransaction() {
// 业务逻辑代码
}
二、事务的传播行为
事务的传播行为是指当一个事务方法被另一个事务方法调用时,两者之间的事务应该如何关联。通过配置不同的传播行为,可以控制是否应该创建新的事务、加入现有事务或者以非事务方式执行等。
Spring 提供了七种标准的事务传播行为,它们可以通过 @Transactional 注解的 propagation 属性来指定。以下是这些传播行为的详细说明:
PROPAGATION_REQUIRED (默认):
如果当前存在事务,则加入该事务;如果不存在,则创建一个新的事务。
这是最常用的传播行为,适用于大多数场景。
PROPAGATION_SUPPORTS
如果当前存在事务,则加入该事务;如果不存在,则以非事务方式执行。
适合那些对事务性没有特别要求的操作,如查询操作。
PROPAGATION_MANDATORY:
如果当前存在事务,则加入该事务;如果不存在,则抛出异常(IllegalTransactionStateException)。
用于强制要求在已有事务中执行的方法。
PROPAGATION_REQUIRES_NEW:
创建一个新的事务,如果当前存在事务,则将当前事务挂起。
适用于需要独立于外部事务执行的业务逻辑,确保内部操作不会影响外部事务的结果。
PROPAGATION_NOT_SUPPORTED:
以非事务方式执行操作,如果当前存在事务,则将当前事务挂起。
适合那些明确不需要事务的操作,如读取系统配置或发送邮件等。
PROPAGATION_NEVER:
以非事务方式执行,如果当前存在事务,则抛出异常(IllegalTransactionStateException)。
用于严格禁止在事务环境中执行的方法。
PROPAGATION_NESTED:
如果当前存在事务,则在嵌套事务内执行;如果不存在,则创建一个新的事务。
嵌套事务是外部事务的一部分,但可以独立于外部事务进行提交或回滚。这种传播行为依赖于底层数据库和驱动的支持,例如 MySQL 的 InnoDB 引擎支持保存点(SAVEPOINT),从而实现嵌套事务。
注意事项
性能考虑:选择合适的传播行为对于性能优化非常重要。例如,PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NOT_SUPPORTED 都会涉及到事务的挂起和恢复,这可能会带来额外的开销。
事务边界:正确理解事务的边界以及传播行为的影响,有助于避免潜在的问题,如死锁、数据不一致等。
嵌套事务支持:不是所有的数据库都支持嵌套事务。使用 PROPAGATION_NESTED 时,请确保你的数据库和驱动程序支持这一特性。
根据应用的具体需求选择适当的传播行为,可以帮助你更好地管理事务,确保数据的一致性和完整性。
三、Spring事务中存在的坑
在同一个类里面,编写两个方法,内部调用的时候,会导致事务设置失效。原因是没有用到
代理对象的缘故。具体来说:
Spring 使用 AOP 来实现事务管理,它会为每个带有 @Transactional 注解的方法创建一个代理对象。当你通过 Spring 容器获取这个类的实例并调用其方法时,实际上是调用了代理对象的方法,而不是原始类的方法。代理对象负责在方法调用前后插入事务管理逻辑。
然而,当你在一个类的非静态方法中直接调用另一个 @Transactional 方法时,调用并没有经过代理对象,而是直接调用了原始类的方法。因此,事务管理逻辑不会被应用,导致事务设置失效。
方法1:
1)、导入spring-boot-starter-aop依赖
2)、启动类添加注解@EnableAspectJAutoProxy(exposeProxy=true)
3)、事务使用的地方使用AopContext.currentProxy() 调用方法。
使用示例:
import org.springframework.aop.framework.AopContext;@Service
public class MyService {@Transactionalpublic void transactionalMethod() {// 事务逻辑}public void performOperation() {// 业务逻辑((MyService) AopContext.currentProxy()).transactionalMethod();}
}
不过这种方式使得代码更加复杂且不直观,因此尽量避免使用,除非绝对必要。
最推荐的做法是将事务方法移到不同的类中。这样可以确保每次调用事务方法时都通过代理对象进行,从而保证事务管理生效。具体可参考方法2:
方法2:
@Service
public class MyService {@Autowiredprivate AnotherService anotherService;public void performOperation() {// 业务逻辑anotherService.transactionalMethod();}
}@Service
public class AnotherService {@Transactionalpublic void transactionalMethod() {// 事务逻辑}
}
拓展:@Transactional支持的配置属性大盘点
除了上面提到的propagation和isolation,@Transactional 注解里边还支持配置以下属性:
1. value 或 transactionManager
- 作用:指定要使用的事务管理器的名称。如果你的应用程序中有多个事务管理器(例如,针对不同的数据源),你可以使用这个属性来明确指定哪一个事务管理器应该管理当前方法的事务。
- 默认值:
"transactionManager",这是 Spring 默认的事务管理器 Bean 名称。
@Transactional("myTransactionManager")
public void myTransactionalMethod() { // 业务逻辑 }
2. readOnly
- 作用:指定事务是否为只读事务。只读事务通常用于查询操作,可以提高性能(例如,禁用脏页写入等)。
- 取值:
false(默认):事务不是只读的,允许进行插入、更新和删除操作。true:事务是只读的,仅允许查询操作。
@Transactional(readOnly = true)
public List<Entity> findAllEntities() { // 查询操作 }
3. timeout
作用:定义事务的超时时间(单位为秒)。如果事务在指定时间内未能完成,Spring 会自动回滚事务。
默认值:-1,表示使用后端数据库或事务管理器的默认超时设置。
@Transactional(timeout = 30)
public void longRunningOperation() { // 长时间运行的业务逻辑 }
4. rollbackFor
作用:指定哪些异常应该触发事务回滚。默认情况下,只有未检查异常(如 RuntimeException 及其子类)会触发回滚。你可以通过这个属性指定其他异常类型也应触发回滚。
取值:一个或多个异常类,可以用逗号分隔。
@Transactional(rollbackFor = {CustomCheckedException.class, AnotherException.class}) public void methodThatMayThrowExceptions() { // 业务逻辑 }
5. noRollbackFor
作用:指定哪些异常不应该触发事务回滚。默认情况下,所有未检查异常都会触发回滚,但你可以通过这个属性指定某些异常不应触发回滚。
取值:一个或多个异常类,可以用逗号分隔。
@Transactional(noRollbackFor = CustomCheckedException.class)
public void methodThatMayThrowCustomException() { // 业务逻辑 }
6. validation
作用:指定是否在事务开始之前验证事务属性。如果设置为 true,Spring 会在事务开始前检查事务属性是否符合要求,如果不符则抛出异常。
默认值:false,即不进行验证。
@Transactional(validation = true)
public void validateTransactionalAttributes() { // 业务逻辑 }
相关文章:
Springboot @Transactional使用时需注意的几个问题
一、事务的隔离级别 在Springboot应用中,如果我们想实现方法一旦执行有异常产生,就触发事务回滚,可以在方法上面添加Transactional注解。如果应用采用mysql数据库,虽然mysql本身也有事务隔离机制,但在Sping数据库的应…...
数字经济下的 AR 眼镜
目录 1. 📂 AR 眼镜发展历史 1.1 AR 眼镜相关概念 1.2 市面主流 XR 眼镜 1.3 AR 眼镜大事记 1.4 国内外 XR 眼镜 1.5 国内 AR 眼镜四小龙 2. 🔱 关键技术 2.1 AR 眼镜近眼显示原理 2.2 AR 眼镜关键技术 2.3 AR 眼镜技术难点 3. Ὂ…...
力扣150题
88. 合并两个有序数组 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。 **注意:**…...
剑指offer搜索二维矩阵
题目连接 https://leetcode.cn/problems/search-a-2d-matrix-ii/’ 代码 自己想出来的 解法一 初始化两个指针,i0,j列数-1 若此时matrix[i][j]target 则返回true 若此时matrix[i][j]>target,表明在第j列中不可能存在target,因为列是升序的 若此时ma…...
如何设置浏览器不缓存网页
设置浏览器不缓存网页可以通过多种方法实现,以下是一些常见的策略: HTTP响应头控制: Cache-Control:这是最常用的HTTP头之一,用于控制响应的缓存行为。例如: Cache-Control: no-cache, no-store, must-r…...
Iris简单实现Go web服务器
package mainimport ("github.com/kataras/iris" )func main() {app : iris.New() // 实例一个iris对象//配置路由app.Get("/", func(ctx iris.Context) {ctx.WriteString("Hello Iris")})app.Get("/aa", func(ctx iris.Context) {ct…...
后端项目java中字符串、集合、日期时间常用方法
我这里只介绍了项目中最常用的哈,比如像集合有很多,但我们最常用的就是ArrayList。 然后我这里会以javascript中的字符串、数组的方法为基准来实现,有些方法js和java会有些区别也会介绍 字符串 每次修改 String 对象都会创建一个新的对象,而 StringBuffer 可以在同一个对象…...
【Spring事务】深入浅出Spring事务从原理到源码
什么是事务 保证业务操作完整性的一种数据库机制 (driver 驱动)事务特定 ACID A 原子性 (多次操作 要不一起成功 要不一起失败 (部分失败 savepoint)) C 一致性 (事务开始时数据状态,…...
vue.js滑动到顶便锁定位置
<template><div><div class"nav"></div><div class"searchBar" id"searchBar"><ul :class"searchBarFixed true ? isFixed :"> <li>区域<i class"iconfont icon-jiantouxia"…...
EdgeX Core Service 核心服务之 Core Command 命令
EdgeX Core Service 核心服务之 Core Command 命令 一、概述 Core-command(通常称为命令和控制微服务)可以代表以下角色向设备和传感器发出命令或动作: EdgeX Foundry中的其他微服务(例如,本地边缘分析或规则引擎微服务)EdgeX Foundry与同一系统上可能存在的其他应用程序…...
掌握常用HTML标签:创建个人简介网页
任务目标 理解HTML文档的基本结构,掌握常见的HTML标签及其用途,创建一个简单的个人简介网页。 学习内容脑图 #mermaid-svg-5GTdqH41gawr4v0h {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
音视频学习(二十五):ts
TS(MPEG-TS,MPEG Transport Stream) 是一种广泛应用于流媒体传输和存储的容器格式。它最早由 MPEG(Moving Picture Experts Group)组织制定,用于视频和音频的压缩编码。在 HLS(HTTP Live Stream…...
10. 虚拟机VMware Workstation Pro下共享Ubuntu和Win11文件夹
本文记录当前最新版虚拟机VMware Workstation Pro(2024.12)如何在win11下共享文件,以实现Windows与Ubuntu互传文件的目的。 1. 创建共享文件夹 1.1 先关闭虚拟机的客户机,打开虚拟机设置 1.2 在虚拟机设置界面找到“选项”->“…...
单元测试mock框架Mockito
为了继续改进 Mockito 并进一步改善单元测试体验,我们希望您升级到 2.1.0!Mockito 遵循语义版本控制,仅在主要版本升级时包含重大更改。在库的生命周期中,重大更改是推出一组全新功能所必需的,这些功能会改变现有行为甚…...
Python从0到100(七十八):神经网络--从0开始搭建全连接网络和CNN网络
前言: 零基础学Python:Python从0到100最新最全教程。 想做这件事情很久了,这次我更新了自己所写过的所有博客,汇集成了Python从0到100,共一百节课,帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…...
2024多模态大模型综述最新总结
摘要 随着人工智能技术的快速发展,多模态大模型(MLLM)已成为研究的新热点。这些模型以强大的大型语言模型(LLM)为基础,能够处理和理解多种模态信息,如文本、图像、视频和音频。本文综述了MLLM的…...
Redis——缓存穿透
文章目录 1. 问题介绍1.1 定义1.2 举例 2. 解决方案2.1 方案一:空值缓存2.1.1 做法2.1.2 举例2.1.3 示例代码2.1.4 优点2.1.5 缺点 2.2 方案二:布隆过滤器2.2.1 思想2.2.2 做法2.2.3 示例代码2.2.4 优点2.2.5 缺点 2.3 方案三:限流3. 总结 1.…...
1.gitlab 服务器搭建流程
前提条件: 一、服务器硬件水平 搭建gitlab服务器最低配置要求2核4G,低于这个配置的服务器运行效果很差。 gitlab官网:https://about.gitlab.com/ 下载地址:gitlab/gitlab-ce - Packages packages.gitlab.com 本机ubuntu 二、安装依赖 su…...
McDonald‘s Event-Driven Architecture 麦当劳事件驱动架构
原文链接 1 mcdonalds-technical-blog/ 原文链接 2 mcdonalds-technical-blog/ 麦当劳在异步、事务性和分析性处理用例中使用跨技术栈的事件,包括移动订单进度跟踪和向客户发送营销通信(交易和促销)。 统一事件平台(unified eve…...
GTID详解
概念和组成 1,全局事务表示:global transaction identifiers 2, GTID和事务一一对应,并且全局唯一 3,一个GTID在一个服务器上只执行一次 4,mysql 5.6.5开始支持 组成 GTID server_uuid:transaction_id 如…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...
Caliper 负载(Workload)详细解析
Caliper 负载(Workload)详细解析 负载(Workload)是 Caliper 性能测试的核心部分,它定义了测试期间要执行的具体合约调用行为和交易模式。下面我将全面深入地讲解负载的各个方面。 一、负载模块基本结构 一个典型的负载模块(如 workload.js)包含以下基本结构: use strict;/…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...
