You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring AOP拦截同注解嵌套方法调用:多数据源路由失效问题

问题原因分析
  • Spring AOP代理机制限制:Spring的@Transactional和自定义AOP切面都基于动态代理实现。当primary()方法内部直接调用replica()时,调用的是原始对象方法而非代理对象方法,因此DataSourceRouteInterceptor的切面逻辑不会触发,无法切换数据源。
  • 事务上下文继承:primary()标注的@Transactional(readOnly=false)会开启主库事务上下文,默认事务传播行为(REQUIRED)会让replica()加入当前主库事务,不会重新选择数据源。
解决方案

步骤1:开启代理对象暴露

在Spring配置类上添加注解,允许通过AopContext获取当前代理对象:

@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
public class AppConfig {
    // 其他配置项
}

步骤2:修改内部调用方式为代理对象调用

调整MyService的primary()方法,通过代理对象调用replica()以触发切面逻辑:

@Service
public class MyService {
    @Autowired
    private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    
    @Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW)
    public List<String> replica() {
        String sqlQuery = "SELECT QUERY";
        return namedParameterJdbcTemplate.query(sqlQuery, (rs, rowNum) -> rs.getString(1));
    }
    
    @Transactional(readOnly = false)
    public List<String> primary() {
        String sqlQuery = "INSERT QUERY";
        namedParameterJdbcTemplate.update(sqlQuery, params);
        
        // 通过代理对象调用,触发切面与新事务
        MyService proxyService = (MyService) AopContext.currentProxy();
        return proxyService.replica();
    }
}

步骤3:调整事务传播行为

将replica()的事务传播行为改为REQUIRES_NEW,确保调用时开启独立的只读事务,强制切换到副本库数据源。若使用默认的REQUIRED,会继承主库事务上下文,无法实现数据源切换。

可选:优化路由线程安全性

确保RoutingDataSource的路由状态存储在ThreadLocal中,避免多线程下状态混乱:

public class RoutingDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal<String> ROUTE_KEY = new ThreadLocal<>();
    
    public static void setReplicaRoute() {
        ROUTE_KEY.set("replica");
    }
    
    public static void clearReplicaRoute() {
        ROUTE_KEY.remove();
    }
    
    @Override
    protected Object determineCurrentLookupKey() {
        return ROUTE_KEY.get();
    }
}
验证效果

修改完成后调用primary()方法时:

  1. 先执行主库插入操作,事务上下文绑定主库;
  2. 通过代理调用replica()时,触发切面设置副本库路由,并开启独立只读事务;
  3. 查询操作路由到副本库,执行完成后清理路由状态,回到主库事务上下文。

内容的提问来源于stack exchange,提问作者Harsh Kanakhara

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 17:32:04