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

Spring Boot多数据源下自定义@ReadReplica注解切换MyBatis数据源咨询

这个需求完全可以实现。你当前配置的是两套独立的MyBatis运行环境,仅支持按Mapper包路径分配数据源,无法实现方法级别的切换,需要调整为动态路由数据源的方案,具体实现步骤如下:

实现步骤

第一步:创建数据源上下文持有类

用ThreadLocal存储当前线程使用的数据源标识,避免线程间互相干扰:

public class DataSourceContextHolder {
    private static final ThreadLocal<String> DATASOURCE_KEY = new ThreadLocal<>();

    public static void setKey(String key) {
        DATASOURCE_KEY.set(key);
    }

    public static String getKey() {
        return DATASOURCE_KEY.get();
    }

    public static void clear() {
        DATASOURCE_KEY.remove();
    }
}

第二步:创建动态路由数据源

继承Spring提供的AbstractRoutingDataSource实现动态数据源路由逻辑:

public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getKey();
    }
}

第三步:替换原有的多数据源配置

删除你现有PrimaryMyBatisConfig和ReadReplicaMyBatisConfig两个配置类,使用统一的动态数据源配置:

@Configuration
@Slf4j
public class DynamicDataSourceConfig {
    @Value("${mybatis.mapper-locations}")
    private String mapperLocations;

    // 主数据源
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }

    // 读副本数据源
    @Bean(name = "readReplicaDataSource")
    @ConfigurationProperties(prefix = "spring.datasource-read-replica")
    public DataSource readReplicaDataSource() {
        return DataSourceBuilder.create().build();
    }

    // 动态路由数据源作为默认数据源
    @Primary
    @Bean(name = "dynamicDataSource")
    public DataSource dynamicDataSource(@Qualifier("primaryDataSource") DataSource primary,
                                        @Qualifier("readReplicaDataSource") DataSource readReplica) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("primary", primary);
        targetDataSources.put("readReplica", readReplica);

        DynamicRoutingDataSource routingDataSource = new DynamicRoutingDataSource();
        routingDataSource.setTargetDataSources(targetDataSources);
        // 默认使用主数据源
        routingDataSource.setDefaultTargetDataSource(primary);
        return routingDataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(dynamicDataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:" + mapperLocations));
        return bean.getObject();
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    @Primary
    public DataSourceTransactionManager transactionManager(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }
}

第四步:编写AOP切面实现注解自动切换数据源

@Aspect
@Component
public class ReadReplicaAspect {
    // 切点修改为你自己项目Mapper接口所在的包路径
    @Pointcut("execution(* com.yourproject.mapper.*.*(..))")
    public void mapperPointcut() {}

    @Around("mapperPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 方法标注@ReadReplica则切换到读副本数据源
        if (method.isAnnotationPresent(ReadReplica.class)) {
            DataSourceContextHolder.setKey("readReplica");
        }
        try {
            return joinPoint.proceed();
        } finally {
            // 执行完后清除上下文,避免线程复用导致数据源串用
            DataSourceContextHolder.clear();
        }
    }
}

最后在Spring Boot启动类上添加@EnableAspectJAutoProxy注解开启AOP功能即可。

注意事项

如果存在事务嵌套场景,需要注意:如果外层方法已经开启了主数据源的事务,内层标注@ReadReplica的方法默认不会切换数据源,因为事务会绑定固定的数据库连接。如果需要在事务内切换数据源,需要将读方法的事务传播级别设置为REQUIRES_NEW,但会带来事务拆分的副作用,建议读请求尽量不要包裹在写事务内。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 23:15:03