Spring Boot 事务详解

Spring Boot 事务详解

引言

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

声明式事务管理

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

示例

typescript 复制代码
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class UserService {

    @Transactional
    public void createUser(User user) {
        // 数据库操作
    }
}

AI写代码java
运行
1234567891011

编程式事务管理

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

示例

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

@Service
public class UserService {

    @Autowired
    private PlatformTransactionManager transactionManager;

    public void createUser(User user) {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        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;
        }
    }
}

AI写代码java
运行
12345678910111213141516171819202122232425262728

[事务传播行为]

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

1. REQUIRED

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

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

示例

java 复制代码
@Transactional(propagation = Propagation.REQUIRED)
public void methodA() {
    // 业务逻辑
}

AI写代码java
运行
1234

事务传播示意图

lua 复制代码
+--------+              +--------+
|  方法A  |              |  方法B  |
|        |--------------->        |
|        | 传播事务 T1    |        |
+--------+              +--------+

AI写代码
12345

2. SUPPORTS

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

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

示例

java 复制代码
@Transactional(propagation = Propagation.SUPPORTS)
public void methodB() {
    // 业务逻辑
}

AI写代码java
运行
1234

事务传播示意图

lua 复制代码
+--------+              +--------+
|  方法A  |              |  方法B  |
|        |--------------->        |
|        | 传播事务 T1    |        |
+--------+              +--------+

AI写代码
12345

3. MANDATORY

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

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

示例

java 复制代码
@Transactional(propagation = Propagation.MANDATORY)
public void methodC() {
    // 业务逻辑
}

AI写代码java
运行
1234

事务传播示意图

lua 复制代码
+--------+              +--------+
|  方法A  |              |  方法C  |
|        |--------------->        |
|        | 传播事务 T1    |        |
+--------+              +--------+

AI写代码
12345

4. REQUIRES_NEW

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

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

示例

java 复制代码
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodD() {
    // 业务逻辑
}

AI写代码java
运行
1234

事务传播示意图

lua 复制代码
+--------+              +--------+
|  方法A  |              |  方法D  |
|        |------------->|        |
| 挂起事务 T1           | 创建事务 T2 |
+--------+              +--------+

AI写代码
12345

5. NOT_SUPPORTED

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

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

示例

java 复制代码
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void methodE() {
    // 业务逻辑
}

AI写代码java
运行
1234

事务传播示意图

lua 复制代码
+--------+              +--------+
|  方法A  |              |  方法E  |
|        |------------->|        |
| 挂起事务 T1           | 非事务执行 |
+--------+              +--------+

AI写代码
12345

6. NEVER

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

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

示例

java 复制代码
@Transactional(propagation = Propagation.NEVER)
public void methodF() {
    // 业务逻辑
}

AI写代码java
运行
1234

事务传播示意图

lua 复制代码
+--------+              +--------+
|  方法A  |              |  方法F  |
|        |------------->|        |
|        | 如果存在事务 T1,抛异常 |
+--------+              +--------+

AI写代码
12345

7. NESTED

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

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

示例

java 复制代码
@Transactional(propagation = Propagation.NESTED)
public void methodG() {
    // 业务逻辑
}

AI写代码java
运行
1234

事务传播示意图

lua 复制代码
+--------+              +--------+
|  方法A  |              |  方法G  |
|        |------------->|        |
| 事务 T1             | 嵌套事务 T1.1 |
+--------+              +--------+

AI写代码
12345

事务失效情况

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 属性配置回滚:

示例

csharp 复制代码
@Transactional(rollbackFor = IOException.class)
public void methodH() {
    // 业务逻辑
}

AI写代码java
运行
1234

事务属性

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

1. 隔离级别

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

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

示例

java 复制代码
@Transactional(isolation = Isolation.READ_COMMITTED)
public void methodI() {
    // 业务逻辑
}

AI写代码java
运行
1234

2. 事务超时

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

示例

java 复制代码
@Transactional(timeout = 30)
public void methodJ() {
    // 业务逻辑
}

AI写代码java
运行
1234

3. 只读事务

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

示例

typescript 复制代码
@Transactional(readOnly = true)
public void methodK() {
    // 业务逻辑
}

AI写代码java
运行
1234

4. 回滚规则

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

示例

csharp 复制代码
@Transactional(rollbackFor = Exception.class)
public void methodL() {
    // 业务逻辑
}

AI写代码java
运行
1234

常见面试题解析

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 注解可以方便地配置事务的传播行为和属性。理解和合理应用这些配置,可以有效地提高应用程序的数据一致性和完整性。

相关推荐
神奇小汤圆12 分钟前
MySQL / MariaDB 主从复制架构实战指南
后端
用户67570498850215 分钟前
【AI开发实战】从想法到上线,我用AI全栈开发了一款记账微信小程序
后端·aigc·ai编程
Moment16 分钟前
作为前端,如果使用 Langgraph 实现第一个 Agent
前端·javascript·后端
神奇小汤圆17 分钟前
高并发接口总被打崩?我用 ArrayBlockingQueue + 底层源码深度剖析搞定流控
后端
木易 士心18 分钟前
MyBatis Plus 核心功能与用法
java·后端·mybatis
Victor35619 分钟前
MongoDB(93)如何使用变更流跟踪数据变化?
后端
用户67570498850220 分钟前
全网都在推 Claude Code,但只有这篇文章教你如何“真正”能用
后端·aigc·claude
Victor35623 分钟前
MongoDB(94)什么是MongoDB Atlas?
后端
苏三说技术33 分钟前
为什么越来越多的大厂抛弃MCP,转向CLI?
后端
Rust研习社43 分钟前
Rust 写时克隆智能指针 Cow
后端·rust·编程语言