Spring事务管理深度解析:原理、实践与陷阱

Spring事务管理深度解析:原理、实践与陷阱

一、事务基础概念

ACID原则

  • 原子性(Atomicity):事务内的操作要么全部成功,要么全部回滚
  • 一致性(Consistency):事务前后数据库状态保持一致
  • 隔离性(Isolation):并发事务间相互隔离
  • 持久性(Durability):事务提交后数据永久存储

二、Spring事务核心接口

java 复制代码
public interface PlatformTransactionManager {
    TransactionStatus getTransaction(TransactionDefinition definition);
    void commit(TransactionStatus status);
    void rollback(TransactionStatus status);
}

public interface TransactionDefinition {
    int getIsolationLevel();
    int getPropagationBehavior();
    int getTimeout();
    boolean isReadOnly();
}

三、事务配置方式

1. 声明式事务(推荐)

xml 复制代码
<!-- XML配置 -->
<tx:annotation-driven transaction-manager="txManager"/>

<bean id="txManager" 
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
java 复制代码
// 注解驱动
@Configuration
@EnableTransactionManagement
public class AppConfig {
    @Bean
    public PlatformTransactionManager transactionManager(DataSource ds) {
        return new DataSourceTransactionManager(ds);
    }
}

2. 编程式事务

java 复制代码
transactionTemplate.execute(status -> {
    try {
        userDao.update(user1);
        logDao.insert(log);
        return true;
    } catch (Exception e) {
        status.setRollbackOnly();
        return false;
    }
});

四、@Transactional详解

属性配置

java 复制代码
@Transactional(
    propagation = Propagation.REQUIRED,
    isolation = Isolation.READ_COMMITTED,
    timeout = 30,
    readOnly = false,
    rollbackFor = {BusinessException.class},
    noRollbackFor = {SystemException.class}
)
public void businessMethod() { ... }

传播行为(Propagation)

行为类型 说明
REQUIRED(默认) 存在事务则加入,没有则新建
REQUIRES_NEW 总是新建事务,挂起当前事务
NESTED 嵌套事务,使用保存点实现部分回滚
SUPPORTS 存在事务则加入,没有则以非事务运行
NOT_SUPPORTED 非事务执行,挂起当前事务
MANDATORY 必须存在事务,否则抛异常
NEVER 必须非事务执行,否则抛异常

隔离级别(Isolation)

级别 脏读 不可重复读 幻读 说明
READ_UNCOMMITTED 最低隔离级别
READ_COMMITTED(默认) × 避免脏读
REPEATABLE_READ × × MySQL默认级别
SERIALIZABLE × × × 最高隔离级别

五、事务失效场景

  1. 非public方法:基于代理的AOP无法拦截private方法

  2. 自调用问题 :类内部方法调用不会经过代理对象
    解决方案

    java 复制代码
    @Autowired
    private ApplicationContext context;
    
    public void methodA() {
        context.getBean(ThisClass.class).methodB();
    }
  3. 异常类型不匹配:默认只回滚RuntimeException和Error

  4. 多线程调用:不同线程属于不同事务上下文

  5. 错误捕获异常 :catch后未重新抛出

    java 复制代码
    try { ... } 
    catch (Exception e) {
        // 需添加:throw new RuntimeException(e);
    }

六、高级特性

1. 事务同步

java 复制代码
TransactionSynchronizationManager.registerSynchronization(
    new TransactionSynchronization() {
        @Override
        public void afterCommit() {
            // 事务提交后操作
        }
    });

2. 多数据源事务

java 复制代码
@Bean
@Primary
public PlatformTransactionManager primaryTM(DataSource ds1) {
    return new DataSourceTransactionManager(ds1);
}

@Bean
public PlatformTransactionManager secondaryTM(DataSource ds2) {
    return new DataSourceTransactionManager(ds2);
}

// 使用指定事务管理器
@Transactional(transactionManager = "secondaryTM")
public void crossDatabaseOp() {...}

七、最佳实践

  1. 事务方法保持简短,避免远程调用
  2. 明确指定rollbackFor属性
  3. 只读查询添加@Transactional(readOnly=true)
  4. 嵌套事务使用PROPAGATION_NESTED
  5. 监控事务执行时间(超过3秒需优化)
相关推荐
胚芽鞘68124 分钟前
关于java项目中maven的理解
java·数据库·maven
岁忧1 小时前
(LeetCode 面试经典 150 题 ) 11. 盛最多水的容器 (贪心+双指针)
java·c++·算法·leetcode·面试·go
CJi0NG1 小时前
【自用】JavaSE--算法、正则表达式、异常
java
Hellyc2 小时前
用户查询优惠券之缓存击穿
java·redis·缓存
今天又在摸鱼2 小时前
Maven
java·maven
老马啸西风2 小时前
maven 发布到中央仓库常用脚本-02
java·maven
代码的余温2 小时前
MyBatis集成Logback日志全攻略
java·tomcat·mybatis·logback
一只叫煤球的猫4 小时前
【🤣离谱整活】我写了一篇程序员掉进 Java 异世界的短篇小说
java·后端·程序员
斐波娜娜4 小时前
Maven详解
java·开发语言·maven
Bug退退退1234 小时前
RabbitMQ 高级特性之事务
java·分布式·spring·rabbitmq