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,则会抛出异常,因为没有活动的事务。

好处

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

原文地址

相关推荐
《源码好优多》1 小时前
基于SpringBoot+Vue+Uniapp的仓库点单小程序的详细设计和实现
vue.js·spring boot·uni-app
橘子海全栈攻城狮2 小时前
【源码+文档+调试讲解】基于Android的固定资产借用管理平台
android·java·spring boot·后端·python·美食
程序员大金3 小时前
基于SpringBoot+Vue+MySQL的中医院问诊系统
java·javascript·vue.js·spring boot·后端·mysql·tomcat
AskHarries3 小时前
Spring Boot集成RBloomFilter快速入门Demo
java·spring boot·后端
LaLaLa_OvO4 小时前
springboot 用request.setAttribute 传值到控制层
spring boot·后端
paopaokaka_luck4 小时前
基于Spring Boot+Unipp的中考体测训练小程序(协同过滤算法、图形化分析)【原创】
vue.js·spring boot·毕业设计·mybatis·uniapp
IT学长编程5 小时前
计算机毕业设计 网上体育商城系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·计算机毕业设计选题·网上体育商城系统
gobeyye5 小时前
SpringBoot 配置文件
java·spring boot·后端
二十雨辰7 小时前
[瑞吉外卖]01-项目搭建
java·spring boot·mybatis