Spring 声明式事务与传播行为详解:基于高并发业务示例

Spring 声明式事务与传播行为详解

1. 简介

在分布式和高并发系统中,事务管理对于保证数据一致性和系统稳定性至关重要。Spring 提供了声明式事务管理(基于 @Transactional 注解),开发者无需手动管理事务的开启、提交与回滚。通过设置不同的事务传播行为,可以灵活应对业务场景下的方法嵌套、事务独立与局部回滚等需求。

本篇文档将详细介绍:

  • 事务的基本概念及何时存在事务;
  • Spring 中常见的事务传播行为(REQUIRED、REQUIRES_NEW、SUPPORTS、NOT_SUPPORTED、MANDATORY、NEVER、NESTED)的作用及应用场景;
  • 一个完整的高并发业务示例,通过代码展示如何在实际项目中使用这些传播行为。

2. 事务基础概念

2.1 什么是事务?

事务是一系列对数据库操作的逻辑单元,这些操作要么全部执行成功,要么全部回滚,保证数据的原子性、一致性、隔离性和持久性(ACID)。在高并发场景下,事务能防止多个并发操作对同一数据造成冲突或不一致,确保业务数据正确。

2.2 事务何时存在?

在 Spring 中,当你调用标注了 @Transactional 注解的方法时:

  • 如果当前线程中不存在事务,Spring 会在方法执行前启动一个新事务;
  • 如果当前线程已经存在事务,根据设置的传播行为,内层方法可能会加入当前事务或启动新的事务。

因此,事务的存在与否由事务边界决定,也依赖于业务逻辑中方法的调用顺序及其传播设置。


3. Spring 声明式事务传播行为

Spring 中常见的事务传播行为有七种,下面详细说明每种行为的特点及其应用场景:

3.1 Propagation.REQUIRED(默认传播行为)

  • 作用说明:
    如果当前存在事务,则加入该事务;否则,新建一个事务。
  • 应用场景:
    核心业务流程,如下订单操作,其中扣减库存、生成订单记录等必须在同一事务中执行,以确保数据一致性。

3.2 Propagation.REQUIRES_NEW

  • 作用说明:
    总是启动一个新的事务。如果当前存在事务,则会挂起当前事务,新事务执行完毕后再恢复之前的事务。
  • 应用场景:
    用于记录审计日志、发送通知或更新统计数据等辅助操作,这些操作需要独立提交,避免因主事务回滚而影响。

3.3 Propagation.SUPPORTS

  • 作用说明:
    如果当前存在事务,则加入事务;如果没有事务,则以非事务方式执行。
  • 应用场景:
    适用于只读查询操作,既可以在事务中运行,也可以在非事务中执行,从而减少不必要的事务开销。

3.4 Propagation.NOT_SUPPORTED

  • 作用说明:
    总是以非事务方式执行操作;如果当前存在事务,则会挂起事务。
  • 应用场景:
    调用外部系统或接口的场景,比如发送短信、邮件等通知操作,不希望事务管理对性能造成影响。

3.5 Propagation.MANDATORY

  • 作用说明:
    当前方法必须在已经存在的事务中执行,否则抛出异常。
  • 应用场景:
    核心数据操作,如财务记录更新等,要求调用方法必须在事务中进行,以确保数据的一致性。

3.6 Propagation.NEVER

  • 作用说明:
    方法不允许在事务中执行;若调用者存在事务,则抛出异常。
  • 应用场景:
    数据采集或统计操作,不希望事务管理导致额外的锁竞争和性能问题。

3.7 Propagation.NESTED

  • 作用说明:
    如果当前存在事务,则启动一个嵌套事务(利用数据库的保存点机制);如果不存在事务,则行为类似于 REQUIRED。
  • 应用场景:
    在复杂业务流程中,某个子步骤出现异常时只回滚该子步骤,而不影响整个事务的提交,如在订单优惠促销中对局部操作进行保护。

4. 高并发场景下的项目示例

下面的示例项目以订单处理为主线,模拟了高并发环境下的业务操作。项目中:

  • OrderService 使用 REQUIRED 传播行为创建订单;
  • AuditService 使用 REQUIRES_NEW 记录审计日志;
  • 同时引入了其他业务场景,如订单查询(SUPPORTS)、外部通知(NOT_SUPPORTED)、财务处理(MANDATORY)、数据分析(NEVER)及订单促销(NESTED)。

4.1 项目结构概览

com.example.demo
 ├── HighConcurrencyDemoApplication.java
 ├── entity
 │     ├── Order.java
 │     ├── AuditLog.java
 │     ├── FinancialRecord.java
 ├── repository
 │     ├── OrderRepository.java
 │     ├── AuditLogRepository.java
 │     └── FinancialRecordRepository.java
 ├── service
 │     ├── OrderService.java          // REQUIRED 示例(订单创建)
 │     ├── AuditService.java          // REQUIRES_NEW 示例(审计日志)
 │     ├── OrderQueryService.java     // SUPPORTS 示例(订单查询)
 │     ├── ExternalNotificationService.java // NOT_SUPPORTED 示例(外部通知)
 │     ├── FinancialService.java      // MANDATORY 示例(财务处理)
 │     ├── AnalyticsService.java      // NEVER 示例(数据分析)
 │     ├── PromotionService.java      // NESTED 示例(优惠促销)
 │     └── OrderPromotionService.java // 外层业务调用 PromotionService
 └── controller
       ├── OrderController.java       // 高并发订单创建示例
       └── PropagationTestController.java  // 各传播行为测试接口

5. 代码详细展示

下面给出各模块的代码示例。

5.1 应用入口

HighConcurrencyDemoApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class HighConcurrencyDemoApplication {
   
    public static void main(String[] args) {
   
        SpringApplication.run(HighConcurrencyDemoApplication.class, args);
    }
}

5.2 实体定义

Order.java

package com.example.demo.entity;

import javax.persistence.*;

@Entity
@Table(name = "orders")
public class Order {
   
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String product;
    
    private int quantity;

    // getters and setters
    public Long getId() {
    return id; }
    public void setId(Long id) {
    this.id = id; }
    public String getProduct() {
    return product; }
    public void setProduct(String product) {
    this.product = product; }
    public int getQuantity() {
    return quantity; }
    public void setQuantity(int quantity) {
    this.quantity = quantity; }
}

AuditLog.java

package com.example.demo.entity;

import javax.persistence.*;

@Entity
@Table(name = "audit_logs")
public class AuditLog {
   
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private Long orderId;
    
    private String message;

    // getters and setters
    public Long getId() {
    return id; }
    public void setId(Long id) {
    this.id = id; }
    public Long getOrderId() {
    return orderId; }
    public void setOrderId(Long orderId) {
    this.orderId = orderId; }
    public String getMessage() {
    return message; }
    public void setMessage(String message) {
    this.message = message; }
}

FinancialRecord.java
(用于 MANDATORY 示例)

package com.example.demo.entity;

import javax.persistence.*;

@Entity
@Table(name = "financial_records")
public class FinancialRecord {
   
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String description;
    private double amount;

    // getters and setters
    public Long getId() {
    return id; }
    public void setId(Long id) {
    this.id = id; }
    public String getDescription() {
    return description; }
    public void setDescription(String description) {
    this.description = description; }
    public double getAmount() {
    return amount; }
    public void setAmount(double amount) {
    this.amount = amount; }
}

5.3 Repository 接口

OrderRepository.java

package com.example.demo.repository;

import com.example.demo.entity.Order;
import org.springframework.data.jpa.repository.JpaRepository;

public interface OrderRepository extends JpaRepository
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愤怒的代码

如果您有受益,欢迎打赏博主😊

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值