当前位置: 首页 > article >正文

深入解析 Spring 框架中的事务传播行为

目录

(一)REQUIRED

(二)SUPPORTS

(三)MANDATORY

(四)REQUIRES_NEW

(五)NOT_SUPPORTED

(六)NEVER

(七)NESTED


在 Spring 框架中,事务管理是一个至关重要的部分,而事务传播行为则是其中的核心概念之一。它决定了事务在多个方法调用之间的传播方式,对于确保数据的一致性和完整性具有关键作用。下面将详细介绍 Spring 框架中的七种事务传播行为,并结合使用场景说明其重要性。

(一)REQUIRED

  1. 定义:如果当前存在事务,就加入该事务;如果当前没有事务,就创建一个新的事务。这是最常见的选择,也是 Spring 的默认传播行为。
  2. 使用场景示例:在一个电商系统中,用户下单操作涉及订单创建、库存扣除和支付记录等多个步骤。这些步骤需要在同一个事务中完成,以确保数据的一致性。如果在某个步骤出现异常,整个事务应该回滚。此时,可以使用 REQUIRED 传播行为来保证这些操作在同一个事务中执行。例如:
@Service
public class OrderService {
    @Autowired
    private InventoryService inventoryService;
    @Autowired
    private PaymentService paymentService;

    @Transactional(propagation = Propagation.REQUIRED)
    public void createOrder(Order order) {
        inventoryService.reduceStock(order.getProductId(), order.getQuantity());
        paymentService.processPayment(order.getAmount());
        // 其他订单处理逻辑
    }
}

在这个例子中,createOrder 方法使用了 REQUIRED 传播行为。如果调用该方法时已经存在一个事务(例如,在另一个服务方法中开启了事务),那么 createOrder 方法将加入到这个已有的事务中;如果没有现有的事务,它将创建一个新的事务来执行订单创建的逻辑。

(二)SUPPORTS

  1. 定义:如果当前存在事务,就加入该事务;如果当前没有事务,就以非事务方式执行。
  2. 使用场景示例:在一些对性能要求较高且不需要强制事务保证的场景中,可以使用 SUPPORTS 传播行为。例如,在一个日志记录系统中,记录日志操作通常不需要事务支持,但如果在事务环境中调用日志记录方法,可以让它参与到当前事务中。假设有一个系统,在进行业务操作的同时需要记录一些日志信息到数据库。可以使用 SUPPORTS 传播行为的服务方法来实现:
@Service
public class LoggingService {
    @Autowired
    private LogRepository logRepository;

    @Transactional(propagation = Propagation.SUPPORTS)
    public void recordLog(String message) {
        Log log = new Log();
        log.setMessage(message);
        log.setTimestamp(new Date());
        logRepository.save(log);
    }
}

当在事务环境中调用 recordLog 方法时,它会参与到当前事务中;如果在非事务环境中调用,它会以非事务的方式执行,不会开启新的事务。

(三)MANDATORY

  1. 定义:如果当前存在事务,就加入该事务;如果当前没有事务,就抛出异常。
  2. 使用场景示例:适用于必须依赖于外部事务才能执行的场景。例如,在银行转账系统中,转账操作需要在账户服务的事务中进行,以确保两个账户的余额更新操作要么同时成功,要么同时失败。假设有一个账户服务类:
@Service
public class AccountService {
    @Autowired
    private AccountRepository accountRepository;

    @Transactional(propagation = Propagation.MANDATORY)
    public void transfer(Long fromAccountId, Long toAccountId, BigDecimal amount) {
        Account fromAccount = accountRepository.findById(fromAccountId);
        Account toAccount = accountRepository.findById(toAccountId);
        fromAccount.setBalance(fromAccount.getBalance().subtract(amount));
        toAccount.setBalance(toAccount.getBalance().add(amount));
        accountRepository.save(fromAccount);
        accountRepository.save(toAccount);
    }
}

当调用 transfer 方法时,如果当前没有事务存在,就会抛出异常,因为这个方法必须在事务环境中执行,以确保转账操作的原子性。

(四)REQUIRES_NEW

  1. 定义:总是创建一个新的事务。如果当前存在事务,就把当前事务挂起。
  2. 使用场景示例:在一些需要独立于当前事务执行的操作中非常有用。例如,在一个订单系统中,创建订单后需要发送一封确认邮件。发送邮件的操作应该在一个新的事务中执行,以避免邮件发送失败影响订单的创建。假设有一个邮件服务类:
@Service
public class EmailService {
    @Autowired
    private EmailRepository emailRepository;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void sendConfirmationEmail(Order order) {
        Email email = new Email();
        email.setTo(order.getCustomerEmail());
        email.setSubject("Order Confirmation");
        email.setBody("Your order has been processed.");
        emailRepository.save(email);
    }
}

sendConfirmationEmail 方法被调用时,无论调用者是否在事务中,它都会创建一个新的事务来执行发送邮件的操作。这样即使邮件发送失败,也不会影响到订单的创建事务。

(五)NOT_SUPPORTED

  1. 定义:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  2. 使用场景示例:适用于那些不应该与现有事务关联的操作,比如读取数据或执行一些不需要事务支持的计算任务。例如,在一个数据分析系统中,查询某个统计数据的方法可以使用 NOT_SUPPORTED 传播行为,以避免对正在进行的事务造成不必要的干扰:
@Service
public class DataAnalysisService {
    @Autowired
    private DataRepository dataRepository;

    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public BigDecimal calculateAverageValue() {
        List<Data> allData = dataRepository.findAll();
        BigDecimal sum = allData.stream().map(Data::getValue).reduce(BigDecimal.ZERO, BigDecimal::add);
        return sum.divide(new BigDecimal(allData.size()), 2, RoundingMode.HALF_UP);
    }
}

在这个例子中,calculateAverageValue 方法在执行时会挂起任何现有的事务,以非事务的方式计算平均值。

(六)NEVER

  1. 定义:以非事务方式执行,如果当前存在事务,则抛出异常。
  2. 使用场景示例:用于确保某个操作绝对不与现有事务关联的场景。例如,在一个系统中,某些只读操作可能不希望受到事务的影响,因为它们可能会被频繁调用且不需要事务的一致性保证。假设有一个缓存服务类,其中的缓存加载方法可以使用 NEVER 传播行为:
@Service
public class CacheService {
    @Autowired
    private CacheManager cacheManager;

    @Transactional(propagation = Propagation.NEVER)
    public void loadCache() {
        // 从外部数据源加载数据到缓存中的逻辑
    }
}

loadCache 方法被调用时,如果当前存在事务,就会抛出异常,因为它不允许在事务环境中执行。

(七)NESTED

  1. 定义:如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则按 REQUIRED 属性执行。
  2. 使用场景示例:在一些复杂的业务场景中,需要在现有事务的基础上再开启一个子事务,以实现更细粒度的事务控制。例如,在一个大型项目中,某个模块可能需要在另一个模块的事务基础上进行一些额外的操作,但又希望这些操作有自己的事务边界。假设有一个子模块服务类:
@Service
public class SubModuleService {
    @Autowired
    private SubModuleRepository subModuleRepository;

    @Transactional(propagation = Propagation.NESTED)
    public void performSubOperation(Long subModuleId) {
        SubModule subModule = subModuleRepository.findById(subModuleId);
        // 进行子模块相关的操作逻辑
    }
}

performSubOperation 方法在现有事务中被调用时,它会在一个嵌套事务中执行;如果没有现有事务,它会像使用 REQUIRED 传播行为一样创建一个新的事务。

Spring 框架中的七种事务传播行为为开发者提供了灵活的事务管理机制,能够适应各种不同的业务场景。通过合理选择和应用这些传播行为,可以更好地确保数据的一致性和完整性,提高系统的可靠性和稳定性。在实际开发中,需要根据具体的业务需求仔细考虑和选择合适的事务传播行为,以实现最佳的事务管理效果。


http://www.kler.cn/a/513446.html

相关文章:

  • 第23篇 基于ARM A9处理器用汇编语言实现中断<五>
  • 总结5..
  • vue3使用音频audio标签
  • .Net Core微服务入门全纪录(五)——Ocelot-API网关(下)
  • AT8870单通道直流电机驱动芯片
  • 鸿蒙系统 将工程HarmonyOS变成OpenHarmony
  • 视频修复最强算法 部署笔记2025
  • Java面试专题——面向对象
  • JavaScript中的数据类型以及存储上的差别
  • Python----Python高级(文件操作open,os模块对于文件操作,shutil模块 )
  • 深入探究分布式日志系统 Graylog:架构、部署与优化
  • 自动化标注平台开源,基于 yolov8标注平台可本地部署
  • AI 赋能:开启人类 “长生不老” 新纪元?
  • 2025发文新方向:AI+量化 人工智能与金融完美融合!
  • #HarmonyOs篇: 管理应用拥有的状态LocalStorage AppStorage
  • 【Vim Masterclass 笔记25】S10L45:Vim 多窗口的常用操作方法及相关注意事项
  • 从指令角度看函数调用堆栈过程
  • CSDN年度回顾:技术征途上的坚实步伐
  • 路由器缓冲区如何调节的指南说明
  • k8s namespace绑定节点
  • MongoDB的索引与聚合
  • STM32G4xx系列boot0复用为IO注意事项
  • 分布式数据库中间件(DDM)的使用场景
  • 2021版小程序开发3——视图与逻辑
  • 【Python项目】主观题自动阅卷系统
  • Maxwell软件使用问题——旧版本打开新版本(The partner project name of the link cannot be empty)