Spring Boot 事务详解

Spring Boot 事务详解

引言

在现代应用程序中,事务管理是确保数据一致性和完整性的重要机制。Spring Boot 提供了强大的事务管理功能,使得开发者可以轻松地定义和管理事务。本文将详细介绍 Spring Boot 中的事务管理,包括事务传播行为、事务属性以及声明式和编程式事务管理。

声明式事务管理

声明式事务管理是通过注解的方式来管理事务,最常用的注解是 @Transactional。这种方式简单直观,适合大多数场景。

示例

importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;@ServicepublicclassUserService{@TransactionalpublicvoidcreateUser(User user){// 数据库操作}}

编程式事务管理

编程式事务管理是通过编程的方式来手动控制事务,通常使用 PlatformTransactionManagerTransactionTemplate

示例

importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.PlatformTransactionManager;importorg.springframework.transaction.TransactionDefinition;importorg.springframework.transaction.TransactionStatus;importorg.springframework.transaction.support.DefaultTransactionDefinition;@ServicepublicclassUserService{@AutowiredprivatePlatformTransactionManager transactionManager;publicvoidcreateUser(User user){DefaultTransactionDefinition def =newDefaultTransactionDefinition(); def.setName("createUserTransaction"); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);TransactionStatus status = transactionManager.getTransaction(def);try{// 数据库操作 transactionManager.commit(status);}catch(Exception e){ transactionManager.rollback(status);throw e;}}}

事务传播行为

事务传播行为定义了当一个事务方法调用另一个事务方法时,事务如何传播。Spring 提供了多种传播行为,可以通过 @Transactional 注解进行配置。以下是 Spring 支持的传播行为及其使用场景:

1. REQUIRED

定义:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。

使用场景:大多数业务操作都使用该传播行为,因为它确保了调用链上的所有操作都在同一个事务中。

示例

@Transactional(propagation =Propagation.REQUIRED)publicvoidmethodA(){// 业务逻辑}

事务传播示意图

+--------+ +--------+ | 方法A | | 方法B | | |---------------> | | | 传播事务 T1 | | +--------+ +--------+ 

2. SUPPORTS

定义:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。

使用场景:适用于可选的事务操作,例如只读查询。

示例

@Transactional(propagation =Propagation.SUPPORTS)publicvoidmethodB(){// 业务逻辑}

事务传播示意图

+--------+ +--------+ | 方法A | | 方法B | | |---------------> | | | 传播事务 T1 | | +--------+ +--------+ 

3. MANDATORY

定义:如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。

使用场景:用于强制要求在事务环境中执行的方法。

示例

@Transactional(propagation =Propagation.MANDATORY)publicvoidmethodC(){// 业务逻辑}

事务传播示意图

+--------+ +--------+ | 方法A | | 方法C | | |---------------> | | | 传播事务 T1 | | +--------+ +--------+ 

4. REQUIRES_NEW

定义:创建一个新的事务,如果当前存在事务,则将当前事务挂起。

使用场景:适用于必须在一个新事务中执行的操作,例如独立的日志记录。

示例

@Transactional(propagation =Propagation.REQUIRES_NEW)publicvoidmethodD(){// 业务逻辑}

事务传播示意图

+--------+ +--------+ | 方法A | | 方法D | | |------------->| | | 挂起事务 T1 | 创建事务 T2 | +--------+ +--------+ 

5. NOT_SUPPORTED

定义:以非事务方式执行操作,如果当前存在事务,则将当前事务挂起。

使用场景:适用于不需要事务的操作,例如批量数据处理。

示例

@Transactional(propagation =Propagation.NOT_SUPPORTED)publicvoidmethodE(){// 业务逻辑}

事务传播示意图

+--------+ +--------+ | 方法A | | 方法E | | |------------->| | | 挂起事务 T1 | 非事务执行 | +--------+ +--------+ 

6. NEVER

定义:以非事务方式执行,如果当前存在事务,则抛出异常。

使用场景:用于强制要求以非事务方式执行的方法。

示例

@Transactional(propagation =Propagation.NEVER)publicvoidmethodF(){// 业务逻辑}

事务传播示意图

+--------+ +--------+ | 方法A | | 方法F | | |------------->| | | | 如果存在事务 T1,抛异常 | +--------+ +--------+ 

7. NESTED

定义:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则行为与 REQUIRED 类似。

使用场景:适用于需要在主事务中执行的子事务,例如复杂的数据库操作。

示例

@Transactional(propagation =Propagation.NESTED)publicvoidmethodG(){// 业务逻辑}

事务传播示意图

+--------+ +--------+ | 方法A | | 方法G | | |------------->| | | 事务 T1 | 嵌套事务 T1.1 | +--------+ +--------+ 

事务失效情况

Spring Boot 通过 Spring 框架的事务管理模块来支持事务操作。事务管理在 Spring Boot 中通常是通过 @Transactional 注解来实现的。以下是一些常见的事务失效情况:

1. 未捕获异常

如果一个事务方法中发生了未捕获的异常,并且异常未被处理或传播到事务边界之外,那么事务会失效,所有的数据库操作会回滚。

2. 非受检异常

默认情况下,Spring 对非受检异常(RuntimeException 或其子类)进行回滚处理,这意味着当事务方法中抛出这些异常时,事务会回滚。

3. 事务传播属性设置不当

如果在多个事务之间存在事务嵌套,且事务传播属性配置不正确,可能导致事务失效。特别是在方法内部调用有 @Transactional 注解的方法时要特别注意。

4. 多数据源的事务管理

如果在使用多数据源时,事务管理没有正确配置或者存在多个 @Transactional 注解时,可能会导致事务失效。

5. 跨方法调用事务问题

如果一个事务方法内部调用另一个方法,而这个被调用的方法没有 @Transactional 注解,这种情况下外层事务可能会失效。

6. 事务在非公开方法中失效

如果 @Transactional 注解标注在私有方法上或者非 public 方法上,事务也会失效。

7. 使用this调用事务方法

Spring 事务是通过代理对象来控制的,只有通过代理对象的方法调用才会应用事务管理的相关规则。当使用 this 直接调用时,是绕过了 Spring 的代理机制,因此不会应用事务设置。

回滚条件

1. 自动回滚事务

  • 抛出未检查异常(RuntimeException 及其子类),例如:NullPointerException 等。

2. 不会自动回滚

  • 默认情况下,检查异常(如 IOExceptionSQLException 等)不会触发回滚。可以通过 @Transactional 注解的 rollbackFor 属性配置回滚:

示例

@Transactional(rollbackFor =IOException.class)publicvoidmethodH(){// 业务逻辑}

事务属性

除了传播行为,Spring 还提供了一些其他事务属性,可以通过 @Transactional 注解进行配置。

1. 隔离级别

隔离级别定义了一个事务与其他事务隔离的程度。Spring 支持以下几种隔离级别:

  • DEFAULT:使用数据库默认的隔离级别。
  • READ_UNCOMMITTED:读未提交的变更。
  • READ_COMMITTED:读已提交的变更。
  • REPEATABLE_READ:可重复读。
  • SERIALIZABLE:串行化。

示例

@Transactional(isolation =Isolation.READ_COMMITTED)publicvoidmethodI(){// 业务逻辑}

2. 事务超时

事务超时定义了事务在回滚之前可以运行的最长时间(以秒为单位)。

示例

@Transactional(timeout =30)publicvoidmethodJ(){// 业务逻辑}

3. 只读事务

只读事务用于优化只读操作。设置为只读的事务可以提示数据库引擎进行某些优化。

示例

@Transactional(readOnly =true)publicvoidmethodK(){// 业务逻辑}

4. 回滚规则

通过 rollbackFornoRollbackFor 属性可以指定哪些异常会触发事务回滚,哪些不会。

示例

@Transactional(rollbackFor =Exception.class)publicvoidmethodL(){// 业务逻辑}

常见面试题解析

1. 什么是事务传播行为?Spring 提供了哪些事务传播行为?

:事务传播行为定义了当一个事务方法调用另一个事务方法时,事务如何传播。Spring 提供了以下事务传播行为:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。

2. 如何配置事务的隔离级别?Spring 提供了哪些隔离级别?

:可以通过 @Transactional 注解的 isolation 属性配置事务的隔离级别。Spring 提供了以下隔离级别:DEFAULT、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE。

3. 什么是只读事务?如何配置?

:只读事务用于优化只读操作。可以通过 @Transactional 注解的 readOnly 属性配置只读事务。例如:@Transactional(readOnly = true)

4. 如何配置事务的超时时间?

:可以通过 @Transactional 注解的 timeout 属性配置事务的超时时间(以秒为单位)。例如:@Transactional(timeout = 30)

5. 如何指定哪些异常会触发事务回滚?

:可以通过 @Transactional 注解的 rollbackFor 属性指定哪些异常会触发事务回滚。例如:@Transactional(rollbackFor = Exception.class)

总结

Spring Boot 提供了强大的事务管理功能,通过 @Transactional 注解可以方便地配置事务的传播行为和属性。理解和合理应用这些配置,可以有效地提高应用程序的数据一致性和完整性。

Read more

2025年最新最全Linux 系统安装Minio详细教程

2025年最新最全Linux 系统安装Minio详细教程

1.MinIO简介 MinIO 是一款高性能、分布式对象存储系统,专为云原生和容器化环境设计。它采用 Apache License 2.0 开源协议,兼容 Amazon S3 API,支持海量数据的存储与管理。 核心特点 高性能架构 MinIO 使用纠删码技术实现数据冗余,读写速度可达每秒数百 GB,适合高吞吐场景。 兼容 S3 协议 完全兼容 Amazon S3 API,现有基于 S3 的应用无需修改即可迁移到 MinIO。 轻量级部署 单二进制文件即可运行,最低配置仅需 512MB 内存,支持 Kubernetes 和 Docker 快速部署。 多云支持 提供混合云解决方案,能在公有云、私有云和边缘计算环境中无缝运行。 典型应用场景

By Ne0inhk

HarmonyOS 文件预览服务避坑指南:从入门到真香

一、背景引入:这玩意儿是干啥的? 咱今天聊的这个 Preview Kit,中文名儿叫"文件预览服务"。听名字就知道,这玩意儿就是帮你预览文件的。 你可能会问:“预览文件?我自己写个组件不就完了吗?” 嘿,您要真这么想,那我得给您点个赞——有这股劲儿,当年我写代码也是这么想的。但踩了几个坑之后,我就服了。 为啥要用 Preview Kit? 咱说个实际场景: 你在应用里做了个文件管理器,用户点了个 Word 文档,你得让人家看到内容吧?这时候你有几个选择: 1. 自己写解析器:docx、xlsx、pptx、pdf… 您慢慢写,写完了叫我一声 2. 接第三方 SDK:WPS、OnlyOffice,选一个,然后掏钱 3. 用 Preview

By Ne0inhk
【Linux系统编程】(三十五)揭秘 Linux 信号产生:从终端到内核全解析

【Linux系统编程】(三十五)揭秘 Linux 信号产生:从终端到内核全解析

前言         在 Linux 系统中,信号是进程间异步通信的 “信使”,而 “信号产生” 则是这个通信过程的起点。无论是我们熟悉的Ctrl+C终止进程,还是程序运行中出现的段错误、定时器超时,本质上都是信号被触发产生的过程。很多开发者只知道 “信号能终止进程”,却不清楚信号到底是怎么来的 —— 是用户操作触发的?还是系统自动产生的?不同场景下信号的产生机制有何不同?         本文将基于 Linux 内核原理,结合 5 种核心信号产生场景(终端按键、系统命令、函数调用、软件条件、硬件异常),用通俗的语言,带你全方位揭秘信号产生的底层逻辑,让你不仅 “知其然”,更 “知其所以然”。下面就让我们正式开始吧! 一、信号产生的核心本质:谁在 “发送” 信号?         在深入具体场景之前,我们先明确一个核心问题:信号是由谁产生并发送的?答案是操作系统(OS)。         无论信号的触发源头是用户按键、函数调用还是硬件异常,

By Ne0inhk
Linux I/O 多路复用实战:Select/Poll 编程指南

Linux I/O 多路复用实战:Select/Poll 编程指南

前言:本文将详细解析 select 和 poll 系统调用的工作原理与性能瓶颈。由于 epoll 内核机制比较复杂(包含红黑树、就绪队列、回调机制及 LT/ET 模式等),内容量大,将为其单独撰写一篇文章,敬请关注后续更新! 文章目录 * 一、什么是IO多路复用? * 二、select * 1. select参数介绍 * 2. select程序编写 * 3. select性能总结 * 三、poll * 1. poll参数介绍 * 2. poll程序编写 * 3. poll性能总结 一、什么是IO多路复用? IO多路复用的本质是使用一个执行流同时等待多个文件描述符就绪。它解决了阻塞IO中“一个连接需要一个线程”导致的资源消耗过大问题,也解决了非阻塞IO需要不断轮询导致的CPU利用率低的问题。 实现IO多路复用的常用三种方法:select/poll/epoll,接下来我们一一进行学习: 二、

By Ne0inhk