Spring之事务使用指南

Spring之事务使用指南

    • 一、事务的基础概念
      • 1.1 什么是事务?
      • 1.2 事务的ACID特性
      • 1.3 Spring事务的核心优势
    • 二、Spring事务的核心配置
    • 三、事务传播行为(Propagation)
      • 3.1 常用传播行为详解
        • 3.1.1 `REQUIRED`(默认值)
        • 3.1.2 `SUPPORTS`
        • 3.1.3 `REQUIRES_NEW`
        • 3.1.4 `NEVER`
        • 3.1.5 `MANDATORY`
      • 3.2 传播行为选择原则
    • 四、事务隔离级别(Isolation)
      • 4.1 并发事务的三大问题
      • 4.2 隔离级别详解
      • 4.3 配置隔离级别
    • 五、声明式事务实战
      • 5.1 环境准备
      • 5.2 业务实现
        • 5.2.1 Mapper接口(MyBatis)
        • 5.2.2 Service实现
      • 5.3 测试与验证
        • 5.3.1 正常流程(无异常)
        • 5.3.2 异常流程(触发回滚)
    • 六、常见问题与避坑指南
      • 6.1 事务不回滚(@Transactional失效)
        • 6.1.1 异常类型不匹配
        • 6.1.2 方法非public
        • 6.1.3 自调用导致事务失效
      • 6.2 事务超时(Timeout)
      • 6.3 只读事务(readOnly)

事务是保证数据一致性的核心机制,尤其在多步操作的业务场景(如订单创建同时扣减库存)中不可或缺,Spring通过AOP实现了声明式事务管理,简化了传统JDBC手动控制事务的繁琐流程。

一、事务的基础概念

1.1 什么是事务?

事务(Transaction)是由一系列数据库操作组成的逻辑单元,这些操作要么全部成功,要么全部失败(如“创建订单”需同时执行“插入订单记录”和“扣减库存”,两者必须同时成功或同时失败)。

1.2 事务的ACID特性

事务必须满足ACID特性,这是保证数据一致性的基础:

  • 原子性(Atomicity):事务中的操作要么全执行,要么全不执行(如转账时“扣款”和“入账”必须同时成功);
  • 一致性(Consistency):事务执行前后,数据从一个有效状态变为另一个有效状态(如转账前后总金额不变);
  • 隔离性(Isolation):多个事务并发执行时,彼此不干扰(避免脏读、不可重复读等问题);
  • 持久性(Durability):事务提交后,修改永久保存到数据库(即使断电也不丢失)。

1.3 Spring事务的核心优势

传统JDBC事务需要手动控制(conn.setAutoCommit(false)commit()rollback()),而Spring事务的优势在于:

  • 声明式事务:通过注解(@Transactional)或XML配置事务,无需编写事务控制代码;
  • AOP实现:事务逻辑与业务逻辑分离,业务代码只关注核心逻辑;
  • 灵活配置:支持自定义传播行为、隔离级别、超时时间等;
  • 整合方便:与Spring容器无缝集成,支持各种数据源和ORM框架(如MyBatis、Hibernate)。

二、Spring事务的核心配置

Spring事务的核心是@Transactional注解,通过属性配置事务行为,常用属性如下:

属性名作用默认值
propagation事务传播行为(如何处理嵌套事务)Propagation.REQUIRED
isolation事务隔离级别(并发控制)Isolation.DEFAULT(数据库默认)
readOnly是否为只读事务(优化性能)false
timeout事务超时时间(秒,超时自动回滚)-1(无超时)
rollbackFor需要回滚的异常类型(如Exception.classRuntimeException及其子类
noRollbackFor不需要回滚的异常类型

三、事务传播行为(Propagation)

事务传播行为定义了“当一个事务方法调用另一个事务方法时,事务如何传播”,是Spring事务最核心的特性之一。

3.1 常用传播行为详解

3.1.1 REQUIRED(默认值)
  • 规则:如果当前存在事务,则加入该事务;如果没有事务,则创建新事务。
  • 适用场景:大多数业务方法(如订单创建、用户注册)。
@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate StockService stockService;// 传播行为:REQUIRED(默认)@Transactional(propagation = Propagation.REQUIRED)public void createOrder(Order order) {orderMapper.insert(order); // 操作1stockService.reduceStock(order.getProductId()); // 调用另一个事务方法}
}@Service
public class StockService {// 传播行为:REQUIRED@Transactional(propagation = Propagation.REQUIRED)public void reduceStock(Long productId) {// 操作2:扣减库存}
}

执行逻辑
createOrder创建事务→reduceStock加入该事务→若操作1或2失败,整个事务回滚(符合原子性)。

3.1.2 SUPPORTS
  • 规则:如果当前存在事务,则加入该事务;如果没有事务,则以非事务方式执行。
  • 适用场景:可选事务的方法(如查询操作,可在事务中执行,也可单独执行)。
@Service
public class UserService {// 传播行为:SUPPORTS@Transactional(propagation = Propagation.SUPPORTS)public User getUserById(Long id) {// 查询用户(非核心操作,有无事务均可)}
}
3.1.3 REQUIRES_NEW
  • 规则:无论当前是否存在事务,都创建新事务(原事务暂停,新事务独立执行)。
  • 适用场景:需要独立事务的操作(如日志记录,即使主事务失败也需提交)。
@Service
public class OrderService {@Autowiredprivate LogService logService;@Transactionalpublic void createOrder(Order order) {// 主事务操作:创建订单logService.recordLog("创建订单:" + order.getId()); // 调用独立事务方法}
}@Service
public class LogService {// 传播行为:REQUIRES_NEW(独立事务)@Transactional(propagation = Propagation.REQUIRES_NEW)public void recordLog(String content) {// 记录日志(即使主事务回滚,此操作仍会提交)}
}

执行逻辑
主事务执行→recordLog创建新事务→日志记录成功提交→主事务若失败,仅主事务回滚,日志不会回滚

3.1.4 NEVER
  • 规则:如果当前存在事务,则抛出异常;如果没有事务,则以非事务方式执行。
  • 适用场景:绝对不能在事务中执行的方法(如某些特殊查询)。
3.1.5 MANDATORY
  • 规则:如果当前存在事务,则加入该事务;如果没有事务,则抛出异常。
  • 适用场景:必须在事务中执行的方法(如核心业务操作)。

3.2 传播行为选择原则

  • 核心业务方法(如订单、支付):REQUIRED
  • 查询方法:SUPPORTS
  • 独立日志、审计操作:REQUIRES_NEW
  • 必须在事务中执行的方法:MANDATORY

四、事务隔离级别(Isolation)

事务隔离级别定义了“多个事务并发执行时的隔离程度”,用于解决并发问题(脏读、不可重复读、幻读)。

4.1 并发事务的三大问题

问题说明示例
脏读读取到另一个未提交事务的修改事务A修改数据→事务B读取→事务A回滚→事务B读取到无效数据
不可重复读同一事务中多次读取数据不一致事务A读取数据→事务B修改并提交→事务A再次读取,数据不同
幻读同一事务中多次查询,结果集数量不一致事务A查询所有订单→事务B新增订单并提交→事务A再次查询,多了一条记录

4.2 隔离级别详解

Spring支持5种隔离级别,对应数据库的隔离级别:

隔离级别解决问题并发性能适用场景
DEFAULT(默认)数据库默认隔离级别(如MySQL默认REPEATABLE_READ中等大多数场景(推荐)
READ_UNCOMMITTED无(允许脏读、不可重复读、幻读)最高极少使用(对一致性要求极低)
READ_COMMITTED解决脏读较高对一致性有基本要求(如Oracle默认)
REPEATABLE_READ解决脏读、不可重复读中等MySQL默认,大多数业务场景
SERIALIZABLE解决所有问题(串行执行)最低对一致性要求极高(如金融交易)

4.3 配置隔离级别

@Service
public class OrderService {// 设置隔离级别为REPEATABLE_READ@Transactional(isolation = Isolation.REPEATABLE_READ)public void createOrder(Order order) {// 业务逻辑}
}

注意:隔离级别受数据库支持限制(如MySQL支持所有级别,SQL Server不支持READ_UNCOMMITTED),实际以数据库为准。

五、声明式事务实战

以“订单创建”为例,演示事务的完整使用(包含传播行为、异常回滚配置)。

5.1 环境准备

添加Spring事务依赖(已包含在spring-context中),并配置数据源和事务管理器:

@Configuration
@MapperScan("com.example.mapper")
public class SpringConfig {// 数据源配置(省略,需配置正确的JDBC连接)@Beanpublic DataSource dataSource() { ... }// 事务管理器(核心)@Beanpublic PlatformTransactionManager transactionManager(DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}

5.2 业务实现

5.2.1 Mapper接口(MyBatis)
public interface OrderMapper {void insert(Order order);
}public interface StockMapper {void reduceStock(@Param("productId") Long productId, @Param("quantity") Integer quantity);
}
5.2.2 Service实现
@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;@Autowiredprivate StockService stockService;/*** 创建订单(核心业务)* 传播行为:REQUIRED(默认)* 回滚规则:所有Exception都回滚(默认仅RuntimeException回滚,此处扩展)*/@Transactional(rollbackFor = Exception.class)public void createOrder(Order order) throws Exception {// 1. 创建订单orderMapper.insert(order);// 2. 扣减库存(调用另一个事务方法)stockService.reduceStock(order.getProductId(), order.getQuantity());// 3. 模拟异常(测试回滚)if (order.getTotalAmount() < 0) {throw new Exception("订单金额不能为负"); // 触发回滚}}
}@Service
public class StockService {@Autowiredprivate StockMapper stockMapper;// 传播行为:REQUIRED(加入订单事务)@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)public void reduceStock(Long productId, Integer quantity) {stockMapper.reduceStock(productId, quantity);// 若库存不足,抛出异常(触发回滚)if (/* 库存不足 */) {throw new RuntimeException("库存不足");}}
}

5.3 测试与验证

5.3.1 正常流程(无异常)
@Test
public void testCreateOrderSuccess() {Order order = new Order();order.setProductId(1L);order.setQuantity(2);order.setTotalAmount(100.0);orderService.createOrder(order);// 验证:订单表新增记录,库存表数量减少(事务提交成功)
}
5.3.2 异常流程(触发回滚)
@Test
public void testCreateOrderRollback() {Order order = new Order();order.setProductId(1L);order.setQuantity(2);order.setTotalAmount(-100.0); // 触发异常try {orderService.createOrder(order);} catch (Exception e) {// 验证:订单表无新增记录,库存表数量未变(事务回滚成功)}
}

六、常见问题与避坑指南

6.1 事务不回滚(@Transactional失效)

6.1.1 异常类型不匹配

问题:方法抛出CheckedException(如Exception),但rollbackFor未配置,导致事务不回滚。

原因@Transactional默认只对RuntimeException及其子类回滚,对CheckedException不回滚。

解决方案
通过rollbackFor指定需要回滚的异常:

// 对所有Exception回滚
@Transactional(rollbackFor = Exception.class)
6.1.2 方法非public

问题:非public方法(如privateprotected)的@Transactional无效。

原因:Spring AOP默认只对public方法增强(事务基于AOP实现)。

解决方案
确保事务方法为public

6.1.3 自调用导致事务失效

问题:同一类中方法调用(自调用)时,事务不生效。

@Service
public class OrderService {public void methodA() {methodB(); // 自调用,事务不生效}@Transactionalpublic void methodB() { ... }
}

原因:Spring事务基于代理对象,自调用是目标对象内部调用,未经过代理。

解决方案

  1. 注入自身代理对象调用:
@Service
public class OrderService {@Autowiredprivate OrderService orderService; // 注入自身代理public void methodA() {orderService.methodB(); // 通过代理调用,事务生效}@Transactionalpublic void methodB() { ... }
}
  1. 开启暴露代理(@EnableAspectJAutoProxy(exposeProxy = true)),通过AopContext获取代理:
public void methodA() {((OrderService) AopContext.currentProxy()).methodB();
}

6.2 事务超时(Timeout)

问题:事务执行时间过长,占用数据库连接,导致连接池耗尽。

解决方案
设置合理的超时时间(秒),超时自动回滚并释放连接:

// 超时时间30秒
@Transactional(timeout = 30)
public void createOrder(Order order) { ... }

6.3 只读事务(readOnly)

对查询方法设置readOnly = true,提示数据库优化事务(如避免写操作、启用缓存):

// 只读事务(查询方法)
@Transactional(readOnly = true)
public List<Order> getOrders() { ... }

注意:只读事务中执行insert/update会抛出异常(取决于数据库)。

总结:事务使用的最佳实践
Spring事务简化了事务管理,但需遵循最佳实践避免常见问题:

  1. 核心配置
  • 对所有业务方法显式指定rollbackFor = Exception.class(避免异常不回滚);
  • 核心业务用REQUIRED传播行为,独立操作(如日志)用REQUIRES_NEW
  • 查询方法设置readOnly = true优化性能。
  1. 避坑要点
  • 事务方法必须为public
  • 避免自调用(或通过代理对象调用);
  • 合理设置超时时间,避免长事务。
  1. 性能优化
  • 事务范围尽可能小(仅包含必要操作,避免在事务中调用外部接口、等待用户输入);
  • 读多写少场景用较高隔离级别(如READ_COMMITTED),减少锁竞争。

事务是保证数据一致性的最后一道防线,正确使用能避免数据错乱(如重复下单、库存超卖)等严重问题。建议在开发中结合日志(如打印事务开始/提交/回滚日志)和测试(模拟异常验证回滚)确保事务生效。

若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89689.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89689.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于FPGA的多级流水线加法器verilog实现,包含testbench测试文件

目录 1.课题概述 2.系统仿真结果 3.核心程序 4.系统原理简介 5.参考文献 6.完整工程文件 1.课题概述 流水线&#xff08;Pipeline&#xff09;技术源于工业生产中的装配线理念&#xff0c;在数字电路中&#xff0c;它将一个复杂运算任务分解为若干个子任务&#xff0c;每…

5.1.4习题精讲

一、单项选择题 01. 下列部件不属于控制器的是&#xff08; C &#xff09;。 题目原文 下列部件不属于控制器的是&#xff08; &#xff09;。 A. 指令寄存器 B. 程序计数器 C. 程序状态字寄存器 D. 时序电路 正确答案&#xff1a;C 题目解析 考点分析&#xff1a; 本题考察CP…

华为云Flexus+DeepSeek征文|低代码 × 强推理:华为云 Flexus 搭建可部署的 AI Agent 实践方案【搭建宠物养护小知识AI助手】

文章目录华为云FlexusDeepSeek征文&#xff5c;低代码 强推理&#xff1a;华为云 Flexus 搭建可部署的 AI Agent 实践方案【搭建宠物养护小知识AI助手】&#x1f680; 引言一、核心技术概览1. 华为云 Flexus X2. DeepSeek-R1 模型3. Dify 平台二、总体架构设计三、环境准备与资…

基于智慧经营系统的学校住宿登记报表分析与应用探究-毕业论文—仙盟创梦IDE

摘要本文聚焦学校住宿场景&#xff0c;以 “未来之窗智慧经营&#xff08;学校住宿&#xff09;” 系统生成的日报表、昨日报表、本月报表为研究对象&#xff0c;深入剖析报表数据结构、功能价值及在住宿管理中的应用。通过解读水费、电费、押金、房费、总计、订单等数据维度&a…

arping(ARP协议网络测试工具)

1. 项目介绍&#xff1a;arping 是一个用于在局域网&#xff08;LAN&#xff09;中查找特定 IP 地址是否被占用的实用工具。与传统的 ping 命令不同&#xff0c;arping 使用 ARP 协议来发送和接收数据包&#xff0c;从而能够检测到那些阻止 ICMP 请求的主机。arping 可以帮助网…

【UE5医学影像可视化】读取dicom数据生成2D纹理并显示

文章目录1.实现目标2.实现过程2.1 数据准备2.2 创建项目2.3 dcmtk库集成2.4 流程&原理2.5 材质2.6 应用实现3.参考资料1.实现目标 本文在UE5中读取本地的dicom文件&#xff0c;解析像素值、窗宽窗位等信息&#xff0c;生成2D纹理&#xff0c;在UE场景中实现简单的2D医学影像…

lua(xlua)基础知识点记录一

1. 关于 (…) 操作符 编译阶段优化&#xff1a;Lua 编译器会对常量字符串进行优化处理&#xff0c;将连续的字符串拼接操作 (…) 合并为单个字符串。这种优化仅适用于编译期确定的常量字符串&#xff0c;不适用于运行时生成的动态字符串。 示例&#xff1a;local str "He…

【Python数据采集】Python爬取小红书搜索关键词下面的所有笔记的内容、点赞数量、评论数量等数据,绘制词云图、词频分析、数据分析

Python爬取小红书搜索关键词下面的所有笔记的内容、点赞数量、评论数量等数据&#xff0c;绘制词云图、词频分析、数据分析 使用 Python 编写一个简单的爬虫程序来从小红书抓取与指定关键词相关的笔记数据&#xff0c;并对这些数据进行基本的数据分析&#xff0c;包括词云图和…

最大子数组和问题-详解Kadane算法

最大子数组和问题-详解Kadane算法一、问题定义与暴力解法1.1 问题描述1.2 暴力解法的低效性二、Kadane算法的核心原理2.1 动态规划思想的应用2.2 优化空间复杂度三、Kadane算法的Java实现3.1 基础版本&#xff08;处理所有情况&#xff09;3.2 算法正确性验证四、Kadane算法的变…

Mongoose网络库深度解析:从单线程到多线程的架构演进

0. 引言&#xff1a;C/C网络编程的困境与突破 在C/C开发领域&#xff0c;网络编程一直是一个令人头疼的问题。与Python的requests库或Go的net/http包不同&#xff0c;C/C缺乏统一的包管理体系和标准化的网络API。开发者往往需要面对gcc/msvc版本差异、平台兼容性问题、以及各种…

Jfinal+SQLite处理 sqlite数据库执行FIND_IN_SET报错

方法一原代码sql " and FIND_IN_SET(s.M_ID," ids ")"; 修改为 sql " where s.M_ID"getInSql(ids);public static String getInSql(String ids) {String[] idArray ids.split(",");StringBuilder sql new StringBuilder(" I…

day24——Java高级技术深度解析:单元测试、反射、注解与动态代理

文章目录一、单元测试&#xff1a;JUnit框架精要1.1 单元测试核心概念1.2 JUnit快速入门实战基础步骤&#xff1a;断言机制验证结果1.3 JUnit核心注解解析二、反射机制&#xff1a;框架设计的基石2.1 反射核心概念2.2 获取Class对象的三种方式2.3 反射操作类成分获取并执行构造…

网页的性能优化,以及具体的应用场景

下面是每个性能优化技术的具体应用场景示例&#xff0c;结合代码说明如何在实际项目中使用这些优化方法&#xff1a; 1. 批量DOM操作与DocumentFragment 应用场景&#xff1a;动态渲染大量列表项&#xff08;如评论区、商品列表&#xff09; 问题&#xff1a;逐个添加DOM元素会…

Fiddler 中文版 API 调试与性能优化实践 官方中文网全程支持

在现代开发中&#xff0c;性能问题往往是产品上线后最容易被忽视的一环&#xff0c;尤其是API接口性能。一旦接口响应时间过长或在高并发场景下出现性能瓶颈&#xff0c;可能直接影响用户体验和系统稳定性。对于开发者来说&#xff0c;如何精确地找到瓶颈所在&#xff0c;如何模…

嵌入式硬件篇---机械臂运动学解算(3自由度)

实际 3 自由度机械臂的解算是机器人控制的核心&#xff0c;涉及运动学正解&#xff08;关节角度→末端位姿&#xff09;和逆解&#xff08;目标位姿→关节角度&#xff09;。以下从结构建模、解算方法、代码实现和应用场景四个维度详细展开&#xff0c;结合工业级机械臂的典型场…

在摄像机视图中想像在普通 3D 视口里那样随意移动

有两条最常用的方法&#xff1a;1. 「锁定相机到视图」(Lock Camera to View)步骤进入相机视图&#xff1a;按 Numpad 0&#xff08;若无数字键盘&#xff0c;可在 Edit → Preferences → Input 勾选 Emulate Numpad 后用主键盘 0&#xff09;。右侧呼出 N 面板&#xff0c;切…

An End-to-End Attention-Based Approach for Learning on Graphs NC 2025

NC 2025 | 一种基于端到端注意力机制的图学习方法 Nature Communications IF=15.7 综合性期刊 1区 参考:https://mp.weixin.qq.com/s/cZ-d8Sf8wtQ9wfcGOFimCg 今天介绍一篇发表在 Nature Communications 的图学习论文《An end-to-end attention-based approach for learnin…

【牛客刷题】小红的数字串

文章目录 一、题目描述 1.1 输入描述 1.2 输出描述 1.3 示例1 二、高效解法 2.1 核心算法设计 2.2 算法设计理念 2.2.1 算法流程详解 2.2.2 复杂度分析 2.3 算法优势分析 2.3.1 关键优化点 2.3.2 正确性验证 2.4 边界处理 2.5 总结与扩展 一、题目描述 小红拿到了一个数字串(由…

微算法科技技术创新,将量子图像LSQb算法与量子加密技术相结合,构建更加安全的量子信息隐藏和传输系统

随着信息技术的发展&#xff0c;数据的安全性变得尤为重要。在传统计算模式下&#xff0c;即便采用复杂的加密算法&#xff0c;也难以完全抵御日益增长的网络攻击威胁。量子计算技术的出现为信息安全带来了新的解决方案。然而&#xff0c;量子图像处理领域仍面临复杂度高、效率…

博客摘录「 Springboot入门到精通(超详细文档)」2025年7月4日

1.Spring Boot返回Json数据及数据封装1. Controller 中使用RestController注解即可返回 Json 格式的数据首先看看RestController注解包含了什么东西&#xff0c; ResponseBody 注解是将返回的数据结构转换为 Json 格式Target({ElementType.TYPE}) Retention(RetentionPolicy.RU…