Spring AOP事务注解失效问题

问题描述

在某个类中,A方法直接调用同类中的事务方法时,@Transactional 注解失效,导致事务不生效,可能引发数据不一致问题。

代码如下:

public void a() {
    // ❌ 直接调用同类事务方法,@Transactional 失效
    b(); 
}

@Transactional  // 事务注解不生效
public void b() {
    // 数据库操作...
}

原因分析:

Spring AOP 动态代理机制限制:

  • Spring 通过动态代理实现事务管理(@Transactional)
  • 同类内部调用(如 A.a() → A.b())会绕过代理对象
  • 导致事务切面逻辑(事务开启/提交/回滚)未被执行

解决方案:

方案1:事务方法提取到独立服务类

  1. 新建事务服务类

        @Autowired
        private XxxMapper xxxMapper;
        
        @Transactional  // ✅ 事务注解生效
        public void b() {
            xxxMapper.insert();  // 数据库操作
        } } ```
    
  2. 修改任务类调用方式

    @Configuration 
    public class TestService{
        @Autowired
        private TransactionService transactionService;  // 注入事务服务
        
        public void a() {
            // ✅ 通过代理对象调用事务方法
            transactionService.b();
            
            // 其他非事务操作
            cleanTempFiles();
        }
        
        private void cleanTempFiles() {
            // 无需事务的文件操作
        } } ```
    
    

方案2:通过AopContext获取代理

原理:使用 AopContext.currentProxy() 获取当前类的代理对象,通过代理调用方法触发事务

import org.springframework.aop.framework.AopContext;

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true) // 关键配置:暴露代理对象
public class TestService {
    
    @Autowired
    private XxxMapper xxxMapper;
    
    public void a() {
        // 1. 获取当前类的代理对象
        TestService proxy = (TestService) AopContext.currentProxy();
        
        // 2. 通过代理调用事务方法(触发@Transactional)
        proxy.b();
    }

    @Transactional  // ✅ 事务注解生效
    public void b() {
        // 数据库操作
        xxxMapper.insert();
    }
}

配置说明:

  1. 在启动类添加注解:

    @SpringBootApplication 
    @EnableScheduling
    @EnableAspectJAutoProxy(exposeProxy = true) // 启用代理暴露 public class
    Application { ... } 
    
  2. 添加 Maven 依赖:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId> 
    </dependency> 
    

方案3:编程式事务管理(TransactionTemplate)

通过 TransactionTemplate 手动控制事务边界,完全绕过注解机制

import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.transaction.TransactionStatus;

@Configuration
public class TestService {
    
    @Autowired
    private XxxMapper xxxMapper;
    
    @Autowired
    private TransactionTemplate transactionTemplate; // 注入事务模板
    
    public void test() {
        // 1. 使用编程式事务执行数据库操作
        Boolean success = transactionTemplate.execute(status -> {
            try {
                // 事务内的数据库操作
                xxxMapper.insert();
                
                // 可嵌套其他事务操作
                processSubTasks();
                
                return true; // 提交事务
            } catch (Exception e) {
                status.setRollbackOnly(); // 标记回滚
                return false;
            }
        });
        
        // 2. 根据事务结果处理后续逻辑
        if (Boolean.TRUE.equals(success)) {
            cleanTempFiles();
        }
    }

    // 嵌套事务示例
    private void processSubTasks() {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    xxxMapper.updateStatistics();
                } catch (Exception e) {
                    status.setRollbackOnly(); // 子事务回滚
                }
            }
        });
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值