跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Spring 事务与传播机制详解

综述由AI生成Spring 事务管理涵盖编程式与声明式两种实现路径。核心在于理解事务的一致性保障,如转账场景中要么全成功要么全失败。@Transactional 注解简化了事务控制,但需关注其默认行为:仅回滚运行时异常。深入掌握 rollbackFor、隔离级别及七种传播机制(REQUIRED、REQUIRES_NEW 等),能有效解决嵌套调用中的事务边界问题,确保数据操作的可靠性与性能平衡。

林间仙子发布于 2026/3/30更新于 2026/6/312 浏览
Spring 事务与传播机制详解

事务三连

什么是事务

事务是一组操作的集合,是一个不可分割的操作单元。它会把所有的操作作为一个整体,要么一起向数据库提交,要么一起撤销。所以这组操作要么同时成功,要么同时失败。

为什么要有事务

在程序开发中,我们经常面临需要保证数据一致性的场景。比如转账操作: 第一步:A 账户 -100 元。 第二步:B 账户 +100 元。

如果没有事务,第一步执行成功了,第二步执行失败了,那么 A 账户的 100 元就平白无故消失了。使用事务就可以解决这个问题,让这一组操作要么一起成功,要么一起失败。

事务的操作

事务的操作主要有三步: 开启事务:start transaction / begin(一组操作前开启事务) 提交事务:commit(这组操作全部成功,提交事务) 回滚事务:rollback(这组操作中间任何一个操作出现异常,回滚事务)

Spring 中事务的实现

Spring 中的事务操作分为两类: 编程式事务(手动写代码操作事务)。 声明式事务(利用注解自动开启和提交事务)。

准备工作

我们先准备好数据以及访问数据的代码,整体结构如下所示。

架构图

数据库表结构包括 log_info 和 user_info。

log_info

user_info

Spring 编程事务

这种方式需要手动获取事务管理器并控制事务状态。

package com.hbu.springtransdemo.controller;

import com.hbu.springtransdemo.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.web.bind.annotation.RequestMapping;
 org.springframework.web.bind.annotation.RestController;




   {
    
     UserInfoService userInfoService;
    
     DataSourceTransactionManager dataSourceTransactionManager;
     TransactionDefinition transactionDefinition;

    
     String  {
           dataSourceTransactionManager.getTransaction(transactionDefinition);
           userInfoService.registryUser(name, password);
        log.info();
        
        dataSourceTransactionManager.commit(transactionStatus);
        
        
         ;
    }
}
import
@Slf4j
@RestController
@RequestMapping("/User")
public
class
UserController
@Autowired
private
@Autowired
private
private
@RequestMapping("/regist")
public
registryUser
(String name, String password)
TransactionStatus
transactionStatus
=
Integer
result
=
"用户信息插入成功"
// 提交事务
// 回滚事务
// dataSourceTransactionManager.rollback(transactionStatus);
return
"注册成功"

提交事务时,数据库中会增加相应的记录。如果回滚事务,可以看到日志打印的信息:'用户信息插入成功'以及'注册成功',但是刷新数据库没有增加相应的新纪录。

回滚效果

Spring 声明式事务 @Transactional

在需要事务的方法上添加 @Transactional 注解就可以实现。无需手动开启事务和提交事务,进入方法时自动开启事务,方法执行完会自动提交事务,如果中途发生了没有处理的异常会自动回滚事务。

代码也是十分简洁:

package com.hbu.springtransdemo.controller;

import com.hbu.springtransdemo.service.UserInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

import static org.springframework.transaction.annotation.Isolation.READ_COMMITTED;

@Slf4j
@RestController
@RequestMapping("/User2")
public class UserController2 {
    @Autowired
    private UserInfoService userInfoService;

    @Transactional()
    @RequestMapping("/regist")
    public String registryUser(String name, String password) throws IOException {
        Integer result = userInfoService.registryUser(name, password);
        log.info("用户信息插入成功");
        return "注册成功";
    }
}

运行程序,数据插入成功。反之,如果出现异常:

@Transactional()
@RequestMapping("/regist")
public String registryUser(String name, String password) throws IOException {
    Integer result = userInfoService.registryUser(name, password);
    log.info("用户信息插入成功");
    int a = 10 / 0; // 触发异常
    return "注册成功";
}

代码就会回滚,数据没法正常插入数据库。

注意: @Transactional 可以用来修饰方法或类。

  • 修饰方法时:只有修饰 public 方法时才生效(修饰其他方法时不会报错,也不生效)【推荐】。
  • 修饰类时:对 @Transactional 修饰的类中所有的 public 方法都生效。

方法 / 类被 @Transactional 注解修饰时,在目标方法执行开始之前,会自动开启事务,方法执行结束之后,自动提交事务。如果在方法执行过程中,出现异常,且异常未被捕获,就进行事务回滚操作。如果异常被程序捕获,方法就被认为是成功执行,依然会提交事务。

特别的,@Transactional 默认只在遇到运行时异常和 Error 时才会回滚,非运行时异常不回滚。即 Exception 的子类中,除了 RuntimeException 及其子类。

@Transactional 详解

通过上面的代码,我们学习了 @Transactional 的基本使用。接下来我们学习 @Transactional 注解的使用细节。

主要关注三个常见属性:

  1. rollbackFor:异常回滚属性。指定能够触发事务回滚的异常类型。可以指定多个异常类型。
  2. isolation:事务的隔离级别。默认值为 Isolation.DEFAULT。
  3. propagation:事务的传播机制。默认值为 Propagation.REQUIRED。

rollbackFor

前面说了,@Transactional 默认只在遇到运行时异常和 Error 时才会回滚,非运行时异常不回滚。

@Transactional(rollbackFor = Exception.class)
@RequestMapping("/regist")
public String registryUser(String name, String password) throws IOException {
    Integer result = userInfoService.registryUser(name, password);
    log.info("用户信息插入成功");
    if (true) {
        throw new IOException();
    }
    return "注册成功";
}

在上面这种情况下虽然产生异常报错,但是不会产生回滚,数据依旧正常插入数据库。此时我们就可以给 rollbackFor 指定一个回滚的范围,比如此处设置成所有异常类,再运行上面的代码就能正常回滚了。

事务隔离级别

Mysql 事务隔离级别

SQL 标准定义了四种隔离级别,MySQL 全都支持。这四种隔离级别分别是:

  1. 读未提交(READ UNCOMMITTED):该隔离级别的事务可以看到其他事务中未提交的数据。因为其他事务未提交的数据可能会发生回滚,但是该隔离级别却可以读到,我们把该级别读到的数据称之为脏数据,这个问题称之为脏读。
  2. 读提交(READ COMMITTED):该隔离级别的事务能读取到已经提交事务的数据,该隔离级别不会有脏读的问题。但由于在事务的执行中可以读取到其他事务提交的结果,所以在不同时间的相同 SQL 查询可能会得到不同的结果,这种现象叫做不可重复读。
  3. 可重复读(REPEATABLE READ):事务不会读到其他事务对已有数据的修改,即使其他事务已提交。也就可以确保同一事务多次查询的结果一致,但是其他事务新插入的数据,是可以感知到的。这也就引发了幻读问题。可重复读,是 MySQL 的默认事务隔离级别。
  4. 串行化(SERIALIZABLE):序列化,事务最高隔离级别。它会强制事务排序,使之不会发生冲突,从而解决了脏读、不可重复读和幻读问题,但因为执行效率低,所以真正使用的场景并不多。
Spring 事务隔离级别

Spring 中事务隔离级别有 5 种:

  1. Isolation.DEFAULT:以连接的数据库的事务隔离级别为主。
  2. Isolation.READ_UNCOMMITTED:读未提交。
  3. Isolation.READ_COMMITTED:读已提交。
  4. Isolation.REPEATABLE_READ:可重复读。
  5. Isolation.SERIALIZABLE:串行化。
@Transactional(isolation = READ_COMMITTED)
@RequestMapping("/r1")
public String r1(String name, String password) {
    return "r1";
}

可以根据 isolation 属性的赋值来设置隔离级别。

Spring 事务传播机制

事务传播机制就是:多个事务方法存在调用关系时,事务是如何在这些方法间进行传播的。 比如有两个方法 A、B 都被 @Transactional 修饰,A 方法调用 B 方法。A 方法运行时,会开启一个事务。当 A 调用 B 时,B 方法本身也有事务,此时 B 方法运行时,是加入 A 的事务,还是创建一个新的事务呢?这个就涉及到了事务的传播机制。

Spring 事务传播机制有以下 7 种:

  1. Propagation.REQUIRED:默认的事务传播级别。如果当前存在事务,则加入该事务。如果当前没有事务,则创建一个新的事务。
  2. Propagation.SUPPORTS:如果当前存在事务,则加入该事务。如果当前没有事务,则以非事务的方式继续运行。
  3. Propagation.MANDATORY:强制性。如果当前存在事务,则加入该事务。如果当前没有事务,则抛出异常。
  4. Propagation.REQUIRES_NEW:创建一个新的事务。如果当前存在事务,则把当前事务挂起。也就是说不管外部方法是否开启事务,Propagation.REQUIRES_NEW 修饰的内部方法都会新开启自己的事务,且开启的事务相互独立,互不干扰。
  5. Propagation.NOT_SUPPORTED:以非事务方式运行,如果当前存在事务,则把当前事务挂起。
  6. Propagation.NEVER:以非事务方式运行,如果当前存在事务,则抛出异常。
  7. Propagation.NESTED:如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行。如果当前没有事务,则该取值等价于 PROPAGATION_REQUIRED。

接下来我们来演示一下其中几个场景:

1. 都使用默认传播机制(REQUIRED)

@Transactional
@RequestMapping("/r2")
public String r2(String name, String password) {
    userInfoService.registryUser(name, password);
    log.info("新建用户成功");
    logInfoService.insert();
    log.info("新建日志成功");
    return "成功!!!";
}
@Service
public class UserInfoService {
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Transactional(propagation = Propagation.REQUIRED)
    public Integer registryUser(String name, String password) {
        return userInfoMapper.insert(name, password);
    }
}
@Service
public class LogInfoService {
    @Autowired
    private LogInfoMapper logInfoMapper;

    @Transactional(propagation = Propagation.REQUIRED)
    public Integer insert() {
        Integer result = logInfoMapper.insert("zhangsan", "新建用户");
        return result;
    }
}

结构类似于:

结构图

因为本身 r2 就是事务,所以那两个事务会和 r2 一起成为一个事务。此时如果有任意一个事务发生回滚操作,就被认定这个合成的大事务产生回滚,所以整个事务都回滚,每一个事务操作都不生效。当然,正常提交时大家也是都提交。

2. REQUIRES_NEW

REQUIRES_NEW

此时几个事务是独立的,每一个事务提交还是回滚与其他事务无关。

3. NESTED

NESTED

跟 REQUIRED 类似,当主事务回滚,所有事务都回滚。但是 NESTED 允许局部回滚,即调用的小事务回滚,其他的事务可以正常提交。

局部回滚

总结

  1. Spring 中使用事务,有两种方式:编程式事务(手动操作)和声明式事务。其中声明式事务使用较多,在方法上添加 @Transactional 就可以实现了。
  2. 通过 @Transactional (isolation = Isolation.SERIALIZABLE) 设置事务的隔离级别。Spring 中的事务隔离级别有 5 种。
  3. 通过 @Transactional (propagation = Propagation.REQUIRED) 设置事务的传播机制,Spring 中的事务传播级别有 7 种,重点关注 REQUIRED(默认值)和 REQUIRES_NEW。

目录

  1. 事务三连
  2. 什么是事务
  3. 为什么要有事务
  4. 事务的操作
  5. Spring 中事务的实现
  6. 准备工作
  7. Spring 编程事务
  8. Spring 声明式事务 @Transactional
  9. @Transactional 详解
  10. rollbackFor
  11. 事务隔离级别
  12. Mysql 事务隔离级别
  13. Spring 事务隔离级别
  14. Spring 事务传播机制
  15. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 二叉树深度优先搜索算法入门详解
  • 前端实战:520 表白信封动画效果实现
  • GitHub 学生认证与 PyCharm Copilot 配置全流程指南
  • n8n 集成飞书机器人:Webhook 签名与 Crypto 节点实战
  • 数据结构:顺序结构二叉树与堆详解
  • 五种常用的web加密算法
  • 前端转 Java 后端开发指南
  • Ubuntu 24.04 LTS 虚拟机安装与基础环境配置实战
  • AI 实践:Claude Skills 技能详解与实践
  • 内网环境下 Python 自动下载模型的代理配置方案
  • Linux 网络基础:协议分层与数据传输流程
  • Linux 下 Git 版本控制实战:核心三板斧详解
  • 飞算 JavaAI 插件深度体验:AI 辅助开发全流程解析
  • Fabric:开源 AI 集成框架与核心功能解析
  • 利用 AI 智能体快速完成 C 语言与前端课程实训实战指南
  • FPGA 跨时钟域 CDC 处理的三种工程方案
  • Qwen3-VL WebUI 部署稳定性测试:72 小时压测实录
  • Python+AI 入门学习路线与实战代码详解
  • Mac 端百度网盘客户端性能优化与插件原理分析
  • MySQL 约束详解:非空、主键与外键的核心作用

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online