Spring 事务

发布于:2025-03-23 ⋅ 阅读:(123) ⋅ 点赞:(0)

Spring 事务管理是 Spring 框架的核心功能之一,旨在简化数据库事务的复杂性,保障数据一致性和业务逻辑的正确性。以下是 Spring 事务的详细解析,涵盖核心概念、配置方式、实战案例及常见问题。


一、Spring 事务的核心概念

1. 事务的 ACID 特性
  • 原子性(Atomicity)​:事务中的多个操作要么全部成功,要么全部失败。
  • 一致性(Consistency)​:事务执行前后,数据库处于一致状态。
  • 隔离性(Isolation)​:多个并发事务之间互不干扰。
  • 持久性(Durability)​:事务提交后,数据永久保存。
2. Spring 事务管理机制
  • 声明式事务:通过 @Transactional 注解声明事务边界(最常用)。
  • 编程式事务:通过 TransactionTemplate 或 PlatformTransactionManager 手动控制事务。
  • 事务管理器(TransactionManager)​:核心组件,负责事务的创建、提交和回滚。

二、Spring 事务配置

1. 声明式事务配置
@Configuration
@EnableTransactionManagement // 启用事务管理
public class TransactionConfig {

    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}
2. 使用 @Transactional 注解
@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional // 自动管理事务
    public void createUser(User user) {
        userRepository.save(user); // 1. 保存用户
        sendWelcomeEmail(user.getEmail()); // 2. 发送邮件(可能抛出异常)
    }

    private void sendWelcomeEmail(String email) {
        // 模拟邮件发送失败
        if (Math.random() < 0.5) {
            throw new RuntimeException("邮件发送失败");
        }
    }
}
注:

@Transactional 是基于 AOP 实现的,AOP ⼜是使⽤动态代理实现的。如果⽬标对象实现了接⼝,默 认情况下会采⽤ JDK 的动态代理,如果⽬标对象没有实现了接⼝,会使⽤ CGLIB 动态代理。 @Transactional 在开始执⾏业务之前,通过代理先开启事务,在执⾏成功之后再提交事务。如果中途 遇到的异常,则回滚事务。

3. 编程式事务示例
@Service
public class UserService {

    @Autowired
    private PlatformTransactionManager transactionManager;

    @Autowired
    private UserRepository userRepository;

    public void createUserProgrammatically(User user) {
        TransactionDefinition def = TransactionDefinition.withDefaults();
        TransactionStatus status = transactionManager.getTransaction(def);

        try {
            userRepository.save(user);
            sendWelcomeEmail(user.getEmail());
            transactionManager.commit(status); // 提交事务
        } catch (Exception e) {
            transactionManager.rollback(status); // 回滚事务
            throw e;
        }
    }
}

三、事务的传播行为

事务传播行为定义了事务在方法调用链中的传播规则,是 Spring 事务管理的核心难点。常见传播行为包括:

传播行为 说明
REQUIRED(默认)

如果当前没有事务,创建新事务;如果已有事务,加入现有事务。

SUPPORTS

支持事务(如果有),否则以非事务方式执行。
MANDATORY 必须存在事务,否则抛出 IllegalTransactionStateException
REQUIRES_NEW

创建新事务,无论当前是否存在事务。已存在事务会被挂起(需手动回滚)。

修饰的内部⽅法会新开启⾃⼰的事务,且开启的事务相互独⽴,互不⼲扰

NOT_SUPPORTED 以非事务方式执行,如果当前存在事务则挂起。
NEVER 以非事务方式运行,如果当前存在事务,则抛出异常
NESTED 支持嵌套事务(如 Spring Data JPA 的 @Transactional 默认行为)。

 

示例代码
@Service
public class UserService {

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void createOrder(Order order) {
        // 新事务,独立于外部事务
    }

    @Transactional(propagation = Propagation.NESTED)
    public void placeOrder(User user, Order order) {
        userRepository.save(user); // 外部事务
        createOrder(order);       // 嵌套事务
    }
}

四、事务的隔离级别

隔离级别用于解决并发事务之间的干扰问题,如脏读、不可重复读、幻读。

隔离级别 说明
DEFAULT 使用数据库默认隔离级别
READ_UNCOMMITTED 读未提交,可以读取到未提交的事物,但存在脏读
READ_COMMITTED 读已提交,只能读取到已提交的事物,防止脏读,但存在不可重复读
REPEATABLE_READ 可重复读,防止脏读和不可重复读,但存在幻读
SERIALIZABLE 可串行化,防止所有问题(但性能最低)
配置隔离级别
@Transactional(isolation = Isolation.READ_COMMITTED)
public void transferMoney() {
    // 业务逻辑
}

五、事务的生命周期

  1. 开始事务:通过 TransactionManager 开始事务。
  2. 执行业务逻辑:在事务范围内执行数据库操作。
  3. 提交事务:业务成功 → transactionManager.commit()
  4. 回滚事务:业务失败 → transactionManager.rollback()
关键接口
  • PlatformTransactionManager:事务管理器核心接口。
  • TransactionDefinition:定义事务属性(传播行为、隔离级别、超时时间等)。
  • TransactionStatus:事务状态对象,用于控制事务流程。

六、异常处理与事务回滚

1. 默认回滚规则
  • 未捕获异常:默认回滚事务(如 RuntimeException 及其子类)。
  • 已捕获异常:不回滚事务(如 IOException)。
2. 自定义回滚规则

@Transactional(rollbackFor = {CustomException.class, IOException.class})
public void createUser(User user) {
    // 业务逻辑
}
3. 手动触发回滚
try {
    // 业务逻辑
} catch (Exception e) {
    transactionManager.rollback(status);
    throw e;
}

七、数据库事务 vs Spring 事务

对比维度 数据库事务 Spring 事务
管理方式 嵌入式在数据库连接中 与数据库解耦,通过 AOP 实现
事务边界 显式通过 BEGIN/COMMIT/ROLLBACK 通过注解或编程式 API 定义
隔离级别 数据库特定配置 统一配置,兼容多种数据库
扩展性 有限 支持声明式和编程式事务

  • 查询MySQL事务隔离级别:
select @@global.tx_isolation,@@tx_isolation;
      // 全局事务隔离级别     // 当前连接的事务隔离级别



八、实战场景与最佳实践

1. 电商订单流程
@Service
public class OrderService {

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void createOrder(Order order) {
        // 1. 扣减库存(需独立事务,避免与其他订单竞争)
        inventoryService.deduct(order.getSkuId());
        
        // 2. 生成订单(主事务)
        orderDAO.save(order);
        
        // 3. 发送物流事件(异步处理,不影响主事务)
        kafkaTemplate.send("logistics_topic", order);
    }
}
2. 高并发场景优化
  • 缩短事务边界:将大事务拆分为多个小事务。
  • 使用乐观锁:通过版本号或时间戳解决并发冲突。
  • 降低隔离级别:从 SERIALIZABLE 改为 READ_COMMITTED 提升性能。

九、常见问题与解决方案

1. 事务不回滚
  • 原因:捕获了异常但未手动回滚。
  • 解决:在 rollbackFor 中指定需要回滚的异常类型。
2. 大事务导致性能瓶颈
  • 原因:事务长时间占用数据库资源。
  • 解决:分库分表、使用缓存、异步处理非关键操作。
3. 死锁问题
  • 原因:高并发下多个事务竞争同一资源。
  • 解决:设置合理的超时时间、使用 REPEATABLE_READ 隔离级别。

十、总结

Spring 事务管理通过声明式注解和编程式 API,简化了数据库事务的复杂性,核心在于:

  1. 合理划分事务边界:通过 @Transactional 控制事务范围。
  2. 配置传播行为和隔离级别:根据业务需求平衡一致性和性能。
  3. 结合异常处理:确保事务在异常时正确回滚。
  4. 异步化非关键操作:提升主事务性能。

网站公告

今日签到

点亮在社区的每一天
去签到