Spring Boot 事务管理与传播

今天将分享 Spring Boot 事务管理的新主题。

让我们开始吧,我阅读了关于交易管理的示例和博客,所有这些都给出了银行领域的示例。这可能是与主题相关的很好且简单的示例。

假设 A 使用他们的银行账户将钱汇给 B。所以这种情况,

A 向 B 发送 100 美元,让我们看看它是如何完成的。

  1. 开始交易:开始新交易。
  2. UPDATE accounts SET balance = balance --- 100.00 WHERE id = 1: 从 A 的余额中扣除 100 美元。
  3. UPDATE accounts SET balance = balance + 100.00 WHERE id = 2: 向 B 的余额添加 100 美元。
  4. COMMIT:提交事务,使所有更改永久化。

假设数据库或进程内的任何资源不可用。我们必须确保数据库的 ACID,我希望您已经听说过这些概念,

  • Atomicity: 确保事务中的所有操作均成功完成。如果任何操作失败,则整个事务失败,并且数据库保持不变。
  • Consistency: 确保事务将数据库从一种有效状态转变为另一种有效状态。
  • Isolation: 确保事务的中间状态对其他事务不可见。
  • Durability: 确保事务一旦提交,即使在系统出现故障的情况下,事务也将保持不变。

我们必须确保在这个关键点上,业务逻辑需要事务管理。它必须决定是回滚整个事务、撤消更改,还是提交事务、确认迄今为止所做的更改。

此时我们需要事务管理来确保一致性和完整性。我们不需要手动配置事务管理,所有困难的事情都由 spring 完成,我们需要在代码中正确且合适的位置应用注释,就这样。

让我们通过上面的一个例子来清楚地了解它。

@Transactional

Spring 管理事务提供了注解。该注释可以在类和方法上定义。在 Spring Boot 中,事务管理不需要配置。但在 Spring 中,它需要配置。

  • Propagation.REQUIRED: 如果事务已经存在,则该方法将在该事务内执行。如果不存在交易,则会创建一个新交易。
  • Propagation.REQUIRES_NEW: 始终启动一个新事务,并暂停当前事务(如果存在)。
  • Propagation.MANDATORY: 需要现有交易。如果不存在事务,则会抛出异常。
  • Propagation.NESTED: 如果事务存在,则在嵌套事务中执行,否则行为类似于 Propagation.REQUIRED。
  • Propagation.NEVER: 以非事务方式执行,如果存在事务则抛出异常。
  • Propagation.NOT_SUPPORTED: 以非事务方式执行,暂停当前事务(如果存在)。
  • Propagation.SUPPORTS: 如果存在事务,则在事务内执行,否则以非事务方式执行。

我将在本文中解释每一个,所以不必害怕。:)。

Propagation.REQUIRED

@Transactional(propagation = Propagation.REQUIRED)

我经常使用这个东西,这不是唯一的方法。考虑这个例子,

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

    @Autowired
    private MyRepository myRepository;

    @Transactional(propagation = Propagation.REQUIRED)
    public void performOperations() {
        try {
            // Perform some database operations
            myRepository.save(new Entity());
            myRepository.update(existingEntity);

            // If everything is successful, the transaction will be committed
        } catch (Exception e) {
            // If any exception occurs, the transaction will be rolled back
            throw new RuntimeException("Transaction failed", e);
        }
    }
}

@Transactional 注解应用于 performOperations 方法。这告诉 Spring 管理该方法的事务。

propagation = Propagation.REQUIRED 属性指定如果事务已经存在,则该方法将在该事务中执行。如果不存在交易,则会创建一个新交易。

如果在 performOperations 方法中发生任何异常,事务将被回滚,以确保数据库保持一致的状态。

如果该方法成功完成,则将提交事务。

对于这个必需的传播,我们不需要默认提及,它是必需的。

在 Spring 中,@Transactional 注解的默认传播行为是 Propagation.REQUIRED。这意味着如果您没有显式指定传播行为,Spring 将默认使用 Propagation.REQUIRED

这是上一个示例的简化版本,没有明确指定传播行为:

java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

    @Autowired
    private MyRepository myRepository;

    @Transactional
    public void performOperations() {
        try {
            // Perform some database operations
            myRepository.save(new Entity());
            myRepository.update(existingEntity);

            // If everything is successful, the transaction will be committed
        } catch (Exception e) {
            // If any exception occurs, the transaction will be rolled back
            throw new RuntimeException("Transaction failed", e);
        }
    }
}

所以我忘了提到 Spring 中的 AOP(面向方面编程)。事务管理是通过面向方面编程(AOP)来促进的。 AOP 有效地将横切关注点与核心业务逻辑分开。在典型的n层架构中,包括表示层(API层)、业务层(服务层)和数据访问层(存储层),横切关注点通常在业务层内定义。这些问题涵盖安全性、验证、事务管理、日志记录、性能优化和其他相关流程等方面。这确实增强了代码的清晰度。我仍在学习 Spring Framework 和 Spring Boot。

Spring 中的面向方面编程 (AOP)

AOP 是一种编程范式,旨在通过允许分离横切关注点来提高模块化性。在 Spring 的上下文中,AOP 用于跨多个方法或类应用事务管理、日志记录、安全性和验证等行为,而无需修改底层代码。

使用 AOP 进行事务管理

Spring 的事务管理是如何使用 AOP 来分离横切关注点的经典示例。当您使用 @Transactional 注释方法或类时,Spring 使用 AOP 围绕注释方法编织事务管理。这意味着事务管理逻辑是自动应用的,而不会用事务相关的代码扰乱您的业务逻辑。

典型的 N 层架构

在典型的 n 层架构中,各层通常组织如下:

  • 表示层(API 层):处理用户请求和响应。该层负责通过 API 公开应用程序的功能。
  • 业务层(Service 层):包含应用程序的核心业务逻辑。该层协调数据流和操作。
  • 数据访问层(Repository 层):与数据库或其他数据源交互。该层负责 CRUD 操作。

跨领域的关注点

横切关注点是影响应用程序多个部分的方面,但不是应用程序的核心功能。这些担忧包括:

  • 事务管理:确保数据库操作以原子方式执行。
  • 安全性:实施访问控制和身份验证。
  • 验证:验证输入数据以确保其满足特定标准。
  • 日志记录:记录重要事件和错误以进行调试和监控。
  • 性能优化:优化应用程序的性能。

使用 AOP 进行事务管理的好处

  • 关注点分离:事务管理逻辑与核心业务逻辑分离,使代码更干净、更易于维护。
  • 可重用性:事务管理可以一致地应用于多个方法和类,而无需重复代码。
  • 可维护性:可以在一处对事务管理逻辑进行更改,从而降低错误和不一致的风险。

对于您的信息-通过使用 AOP 进行事务管理,Spring 可以让开发人员专注于编写业务逻辑,而不必担心事务管理的复杂性。这种方法增强了代码的清晰度、可维护性和模块化性,使开发和维护复杂的应用程序变得更加容易。

回到主题,

第二种传播类型是 Required_new.

REQUIRES_NEW

REQUIRES_NEW 此传播类型对于大多数情况非常有用。如果会话在 REQUIRES_NEW 之前启动,它将挂起前一个会话并创建一个新会话。之前的交易不会影响这一点。这意味着如果前一个事务发生错误,REQUIRES_NEW 将不会受到该错误的影响。

java 复制代码
    @Transactional(propagation = Propagation.REQUIRED)
    public void create(Product product, List<Image> images) {
        saveImages(images);
        productRepository.save(product);
        
    }
    
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void saveImages(List<Image> images) {
        // save images 
    }
使用案例
  • 独立操作:当您需要执行不应受当前事务结果影响的操作时。
  • 错误处理:当您想要确保某些操作在外部事务失败时不会回滚时。
  • 审核日志记录:当您需要独立于主事务记录某些操作时。
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

    @Autowired
    private MyRepository myRepository;

    @Transactional(propagation = Propagation.REQUIRED)
    public void performOperations() {
        try {
            // Perform some database operations within the current transaction
            myRepository.save(new Entity());

            // Call a method that requires a new transaction
            performIndependentOperation();

            // If everything is successful, the transaction will be committed
        } catch (Exception e) {
            // If any exception occurs, the transaction will be rolled back
            throw new RuntimeException("Transaction failed", e);
        }
    }

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void performIndependentOperation() {
        try {
            // Perform some database operations within a new transaction
            myRepository.update(existingEntity);

            // If everything is successful, the new transaction will be committed
        } catch (Exception e) {
            // If any exception occurs, the new transaction will be rolled back
            throw new RuntimeException("Independent operation failed", e);
        }
    }
}
performOperations 方法:

该方法使用 @Transactional(propagation = Propagation.REQUIRED) 注解,这意味着如果存在则加入当前事务,如果不存在则启动一个新事务。 它执行一些数据库操作,然后调用 performIndependentOperation。

performIndependentOperation 方法

该方法使用 @Transactional(propagation = Propagation.REQUIRES_NEW) 注解,这意味着它将始终启动一个新事务,如果存在则暂停当前事务。 它在这个新事务中执行一些数据库操作。

行为,当调用 PerformOperations 时,它会启动一个新事务(或加入一个现有事务)。 当从 performOperations 中调用 performIndependentOperation 时,将启动一个新事务,并挂起当前事务。

如果 performIndependentOperation 成功完成,则提交新事务。 如果 performIndependentOperation 抛出异常,则回滚新事务,但挂起的事务不受影响。 PerformIndependentOperation() 完成后,挂起的事务将恢复。

好处:

  • 隔离:确保 performIndependentOperation 中的操作与主事务隔离。
  • 错误处理:允许更精细的错误处理,因为独立操作的失败不一定会影响主事务。
  • 审核日志记录:对于应独立于主事务进行记录的日志记录或审核操作很有用。

另一种是支持。

Propagation.SUPPORT

Spring 事务管理中的传播行为用于指示如果事务已存在,则方法可以在事务中运行,但如果没有活动的事务,则它也可以非事务方式运行。当您希望方法参与现有事务而不需要启动新事务(如果不存在事务)时,此行为非常有用。

  • 加入现有事务:如果事务已处于活动状态,则该方法将参与该事务。
  • 非事务执行:如果没有活动事务,则该方法将以非事务方式运行。
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

    @Autowired
    private MyRepository myRepository;

    @Transactional(propagation = Propagation.REQUIRED)
    public void performOperations() {
        try {
            // Perform some database operations within the current transaction
            myRepository.save(new Entity());

            // Call a method that supports an existing transaction
            performOptionalTransactionalOperation();

            // If everything is successful, the transaction will be committed
        } catch (Exception e) {
            // If any exception occurs, the transaction will be rolled back
            throw new RuntimeException("Transaction failed", e);
        }
    }

    @Transactional(propagation = Propagation.SUPPORTS)
    public void performOptionalTransactionalOperation() {
        try {
            // Perform some database operations
            myRepository.update(existingEntity);

            // If a transaction is active, this operation will participate in it
            // If no transaction is active, this operation will run non-transactionally
        } catch (Exception e) {
            // Handle exceptions as needed
            throw new RuntimeException("Optional operation failed", e);
        }
    }
}

在此代码中,当调用 performOperations 时,它会启动一个新事务(或加入一个现有事务)。 当从 performOperations 中调用 performOptionalTransactionalOperation 时,它会参与现有事务。 如果在任何事务上下文之外调用 performOptionalTransactionalOperation,它将以非事务方式运行。

Propagation.NOT_SUPPORTED.

Spring 事务管理中的传播行为用于指示方法不应在事务内运行。如果调用该方法时事务处于活动状态,则该事务将挂起,并且该方法以非事务方式运行。此行为对于不需要事务保证的只读操作特别有用,可能会提高性能。

Propagation.NOT_SUPPORTED

  • 挂起现有事务:如果调用该方法时事务处于活动状态,则该事务将挂起。
  • 非事务性执行:该方法以非事务性方式运行。
  • 恢复事务:该方法完成后,恢复暂停的事务。
使用案例
  • 只读操作:当您有只从数据库读取数据而不修改数据的方法时。
  • 性能优化:通过避免只读操作的事务管理开销来提高性能。
  • 外部服务:当调用外部服务或执行不需要事务保证的操作时。
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

    @Autowired
    private MyRepository myRepository;

    @Transactional(propagation = Propagation.REQUIRED)
    public void performOperations() {
        try {
            // Perform some database operations within the current transaction
            myRepository.save(new Entity());

            // Call a method that does not support transactions
            performNonTransactionalOperation();

            // If everything is successful, the transaction will be committed
        } catch (Exception e) {
            // If any exception occurs, the transaction will be rolled back
            throw new RuntimeException("Transaction failed", e);
        }
    }

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void performNonTransactionalOperation() {
        try {
            // Perform some database operations non-transactionally
            myRepository.readData();

            // This operation runs without a transaction, even if a transaction was active
        } catch (Exception e) {
            // Handle exceptions as needed
            throw new RuntimeException("Non-transactional operation failed", e);
        }
    }
}

performOperations 方法:

该方法使用 @Transactional(propagation = Propagation.REQUIRED) 注解,这意味着如果存在则加入当前事务,如果不存在则启动一个新事务。 它执行一些数据库操作,然后调用 performNonTransactionalOperation。

performNonTransactionalOperation 方法:

此方法用 @Transactional(propagation = Propagation.NOT_SUPPORTED) 注释,这意味着它将挂起任何活动事务并以非事务方式运行。 它以非事务方式执行一些数据库操作。

Propagation.NEVER

Spring 事务管理中的传播行为用于指示方法不应在事务内运行。如果调用该方法时事务处于活动状态,则会抛出异常。此行为可确保该方法始终在任何事务上下文之外执行。

使用案例
  • 严格的非事务逻辑:当您的逻辑绝不能成为任何事务的一部分时,例如某些类型的日志记录、审计或其他非数据库操作。
  • 确保非事务性上下文:当您需要确保方法始终在任何事务性上下文之外执行时,无论调用上下文如何。
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MyService {

    @Autowired
    private MyRepository myRepository;

    @Transactional(propagation = Propagation.REQUIRED)
    public void performOperations() {
        try {
            // Perform some database operations within the current transaction
            myRepository.save(new Entity());

            // Call a method that should never run within a transaction
            performNonTransactionalOperation();

            // If everything is successful, the transaction will be committed
        } catch (Exception e) {
            // If any exception occurs, the transaction will be rolled back
            throw new RuntimeException("Transaction failed", e);
        }
    }

    @Transactional(propagation = Propagation.NEVER)
    public void performNonTransactionalOperation() {
        try {
            // Perform some operations that must not be part of a transaction
            myRepository.readData();

            // This operation runs without a transaction, and an exception will be thrown if a transaction is active
        } catch (Exception e) {
            // Handle exceptions as needed
            throw new RuntimeException("Non-transactional operation failed", e);
        }
    }
}

行为: 当调用 performOperations 时,它会启动一个新事务(或加入一个现有事务)。 当从 performOperations 中调用 performNonTransactionalOperation 时,将引发异常,因为事务处于活动状态。 必须在任何事务上下文之外调用 performNonTransactionalOperation 以避免引发异常。

  • 严格执行:确保某些操作永远不会成为任何事务的一部分,从而明确区分事务性和非事务性逻辑。
  • 错误预防:防止在事务中意外包含非事务逻辑,这有助于避免细微的错误并确保正确的行为。

Propagation.mandatory.

Spring 事务管理中的传播行为用于指示方法必须始终在事务内运行。如果调用该方法时没有活动的事务,则会抛出异常。此行为可确保该方法始终在事务上下文中执行,这对于维护数据一致性和完整性至关重要。

Propagation.MANDATORY

  • 需要事务:该方法必须在事务内运行。
  • 无事务异常:如果调用该方法时没有活动事务,则会抛出异常。
使用案例
  • 关键操作:当您的操作必须始终是事务的一部分以确保数据一致性和完整性时,例如金融交易、支付处理或其他关键业务逻辑。
  • 确保事务上下文:当您需要确保方法始终在事务上下文中执行时,无论调用上下文如何。
java 复制代码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class PaymentService {

    @Autowired
    private PaymentRepository paymentRepository;

    @Transactional(propagation = Propagation.REQUIRED)
    public void processPayment(Payment payment) {
        try {
            // Perform some database operations within the current transaction
            paymentRepository.save(payment);

            // Call a method that requires a transaction
            validatePayment(payment);

            // If everything is successful, the transaction will be committed
        } catch (Exception e) {
            // If any exception occurs, the transaction will be rolled back
            throw new RuntimeException("Payment processing failed", e);
        }
    }

    @Transactional(propagation = Propagation.MANDATORY)
    public void validatePayment(Payment payment) {
        try {
            // Perform some validation operations that must be part of a transaction
            paymentRepository.updateStatus(payment, "VALIDATED");

            // This operation runs within a transaction, and an exception will be thrown if no transaction is active
        } catch (Exception e) {
            // Handle exceptions as needed
            throw new RuntimeException("Payment validation failed", e);
        }
    }
}

processPayment 方法:

该方法使用 @Transactional(propagation = Propagation.REQUIRED) 注解,这意味着如果存在则加入当前事务,如果不存在则启动一个新事务。 它执行一些数据库操作,然后调用 validatePayment。

validatePayment 方法:

该方法使用 @Transactional(propagation = Propagation.MANDATORY) 注解,这意味着如果调用该方法时没有事务处于活动状态,则会抛出异常。 它执行一些必须属于事务一部分的验证操作。

当调用 processPayment 时,它会启动一项新交易(或加入现有交易)。

当从 processPayment 中调用 validatePayment 时,它会在现有事务中运行。

如果在任何事务上下文之外调用 validatePayment,则会抛出异常,因为没有活动的事务。

好处

  • 数据一致性:确保关键操作始终在事务内执行,保持数据的一致性和完整性。
  • 错误预防:防止在事务上下文之外意外执行关键操作,这有助于避免细微的错误并确保正确的行为

原文地址

相关推荐
XMYX-06 小时前
Spring Boot + Prometheus 实现应用监控(基于 Actuator 和 Micrometer)
spring boot·后端·prometheus
@yanyu6667 小时前
springboot实现查询学生
java·spring boot·后端
酷爱码8 小时前
Spring Boot项目中JSON解析库的深度解析与应用实践
spring boot·后端·json
java干货9 小时前
虚拟线程与消息队列:Spring Boot 3.5 中异步架构的演进与选择
spring boot·后端·架构
武昌库里写JAVA11 小时前
iview Switch Tabs TabPane 使用提示Maximum call stack size exceeded堆栈溢出
java·开发语言·spring boot·学习·课程设计
小白杨树树12 小时前
【WebSocket】SpringBoot项目中使用WebSocket
spring boot·websocket·网络协议
clk660718 小时前
Spring Boot
java·spring boot·后端
爱敲代码的TOM18 小时前
基于JWT+SpringSecurity整合一个单点认证授权机制
spring boot