遇到的问题之“加入Spring的事务 @Transactional(rollbackFor = Exception.class)导致@DS数据库切换失效”

遇到的问题之“加入Spring的事务  @Transactional(rollbackFor = Exception.class)导致@DS数据库切换失效”

1. 核心问题:事务与数据源的绑定时机

@Service
public class DataService {
    
    @DS("starrocks")  // 希望切换到 StarRocks
    @Transactional     // Spring 事务注解
    public void processData() {
        // 方法体
    }
}

 

执行流程问题:

  1. 事务切面先执行:Spring 的 @Transactional 切面先执行

  2. 获取数据库连接:事务管理器从默认数据源获取连接

  3. 开启事务:在默认连接上开启事务

  4. DS切面后执行:@DS 注解的切面后执行,尝试切换数据源

  5. 数据源切换失败:此时连接已绑定到事务,无法再切换

2. 代码层面的详细分析

// 伪代码:AOP 执行顺序
public Object invoke(MethodInvocation invocation) {
    // 1. 事务切面先执行
    TransactionAspectSupport.beginTransaction();
    //    ↓ 这里获取了默认数据源的连接
    
    // 2. DS切面后执行(如果切面顺序没调整)
    DynamicDataSourceContextHolder.push("starrocks");
    
    // 3. 执行业务方法
    Object result = invocation.proceed();
    
    // 4. DS切面清理
    DynamicDataSourceContextHolder.poll();
    
    // 5. 事务切面提交
    TransactionAspectSupport.commitTransaction();
}

 

3. 具体表现场景

场景1:嵌套服务调用

@Service
public class UserService {
    
    @DS("mysql")  // 主库
    @Transactional
    public void updateUser(User user) {
        userMapper.update(user);
        
        // 调用统计服务
        statsService.updateStats(user);  // 这里可能无法切换到 StarRocks
    }
}

@Service  
public class StatsService {
    
    @DS("starrocks")  // 希望用 StarRocks
    @Transactional(propagation = Propagation.REQUIRES_NEW)  // 新事务
    public void updateStats(User user) {
        // 由于外层已有事务,这里可能仍然使用 MySQL 连接
        statsMapper.insert(user);
    }
}

 

posted @ 2025-12-02 10:49  骚哥  阅读(11)  评论(0)    收藏  举报