Spring Boot实现多数据源动态切换

Spring Boot应用中可以配置多个数据源,并根据注解灵活指定当前使用的数据源

步骤

  1. application.yml中配置数据源信息
    spring:
      datasource:
        ds1:
          driverClassName: org.sqlite.JDBC
          jdbcUrl: jdbc:sqlite::resource:ds1.db
        ds2:
          driverClassName: org.sqlite.JDBC
          jdbcUrl: jdbc:sqlite::resource:ds2.db
    
  2. 实现DataSourceHolder,将当前数据源的key保存在ThreadLocal
    public class DataSourceHolder {
        private static final ThreadLocal<String> HOLDER = new ThreadLocal<>();
    
        public static void setDataSource(String ds) {
            HOLDER.set(ds);
        }
    
        public static String getDataSource() {
            return HOLDER.get();
        }
    
        public static void clear() {
            HOLDER.remove();
        }
    }
    
  3. 基于Spring Boot自带的AbstractRoutingDataSource实现DynamicDataSource
    public class DynamicDataSource extends AbstractRoutingDataSource {
        @Override
        protected Object determineCurrentLookupKey() {
            // 获取代表当前数据源的key
            return DataSourceHolder.getDataSource();
        }
    }
    
  4. 添加配置类DataSourceConfig,向容器中注入所有数据源,并注入一个DynamicDataSource实例作为主数据源,并标注为Primary
    @Configuration
    public class DataSourceConfig {
        /**
         * 数据源1配置
         */
        @Bean("ds1")
        @ConfigurationProperties("spring.datasource.ds1")
        public DataSource ds1() {
            return DataSourceBuilder.create().build();
        }
    
        /**
         * 数据源2配置
         */
        @Bean("ds2")
        @ConfigurationProperties("spring.datasource.ds2")
        public DataSource ds2() {
            return DataSourceBuilder.create().build();
        }
    
        /**
         * 动态数据源配置
         */
        @Bean
        @Primary
        public DataSource dynamicDataSource(@Qualifier("ds1") DataSource ds1, @Qualifier("ds2") DataSource ds2) {
            DynamicDataSource ds = new DynamicDataSource();
            // 设置数据源映射关系
            ds.setTargetDataSources(Map.of(
                    "ds1", ds1,
                    "ds2", ds2
            ));
            // 设置默认数据源
            ds.setDefaultTargetDataSource(ds1);
            return ds;
        }
    }
    
  5. 添加自定义注解Db,标注在方法上,指定方法内部执行时所使用的数据源
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Db {
        String value();
    }
    
  6. 实现切面类DynamicDataSourceAspect,对所有标注了Db注解的方法进行增强
    @Aspect
    @Component
    public class DynamicDataSourceAspect {
        /**
         * Mapper方法切面实现,对所有标注了Db注解的方法生效
         */
        @Around("@annotation(byx.test.Db)")
        public Object around(ProceedingJoinPoint jp) throws Throwable {
            // 获取方法上的Db注解
            MethodSignature methodSignature = (MethodSignature) jp.getSignature();
            Method method = methodSignature.getMethod();
            Db db = method.getAnnotation(Db.class);
    
            try {
                // 方法执行前先设置当前数据源,再执行方法
                DataSourceHolder.setDataSource(db.value());
                return jp.proceed();
            } finally {
                // 方法结束后清理当前数据源
                DataSourceHolder.clear();
            }
        }
    }
    

使用方法

@Mapper
public interface UserMapper {
    @Select("SELECT * FROM users")
    @Db("ds1")
    List<User> listUsersFromDs1();

    @Select("SELECT * FROM users")
    @Db("ds2")
    List<User> listUsersFromDs2();
}

完整代码

https://github.com/byx2000/spring-boot-learning/tree/master/dynamic-data-source

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byx2000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值