SpringBoot实现动态数据源配置和切换

在项目中,大多数情况下一个数据源便可解决问题,但也存在某些情况下,需要多个数据源的支持,像读写分离,或者业务本身很复杂,涉及到多个数据源。本文基于SpringBoot实现动态数据源配置和切换,可应用于多数据源,读写分离等场景。

数据源配置

分别配置了druid.first和druid.second两个数据源

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.jdbc.Driver
    druid:
      first:
        url: jdbc:mysql://localhost:3306/v-sso?useUnicode=true&characterEncoding=UTF-8&useSSL=false
        username: root
        password: 123456
      second:
        url: jdbc:mysql://localhost:3306/v-sso2?useUnicode=true&characterEncoding=UTF-8&useSSL=false
        username: root
        password: 123456
      initial-size: 10
      max-active: 100
      min-idle: 10
      ##省略一些其他配置信息
动态数据源实现

首先定义一个常量存储所有的数据源定义,这里定义了两个数据源,分别为FIRST和SECOND。

public class DataSourceDef {
    public static final String FIRST = "first";
    public static final String SECOND = "second";
}

动态数据源切换的核心是结合AbstractRoutingDataSource实现,通过ThreadLocal实现线程内持有数据源,线程之间持有各自的数据源副本。

public class DynamicDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        //项目启动默认数据源
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }
    
    //设置数据源
    public static void setDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }
	
	//获取数据源
    public static String getDataSource() {
        return contextHolder.get();
    }

	//释放资源
    public static void clearDataSource() {
        contextHolder.remove();
    }
}

定义一个多数据源配置,分别生成两个数据源对应bean对象,同时通过Map实现常量与数据源的绑定。

@Configuration
public class DataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.druid.first")
    public DataSource firstDataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.second")
    public DataSource secondDataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @Primary
    public DynamicDataSource dataSource(DataSource firstDataSource, DataSource secondDataSource) {
        //数据源绑定
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceDef.FIRST, firstDataSource);
        targetDataSources.put(DataSourceDef.SECOND, secondDataSource);
        return new DynamicDataSource(firstDataSource, targetDataSources);
    }
}

至此,我们便实现了多个数据源的配置,但默认的还是第一个数据源,然而我们可能需要切换其他数据源,最好还可以动态切换,这里可通过切面编程实现。

自定义一个数据源注解@DataSource,name则是想要切换的数据源

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {

    String name() default "";
}

通过切面编程实现数据源自动切换

@Aspect
@Component
public class DataSourceAspect {
    @Pointcut("@annotation(com.keduw.vortex.anntation.DataSource)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        DataSource dataSource = method.getAnnotation(DataSource.class);
        if(dataSource == null){
            //默认数据源
            DynamicDataSource.setDataSource(DataSourceDef.FIRST);
        }else {
            //使用注解指定的数据源
            DynamicDataSource.setDataSource(dataSource.name());
        }
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
        }
    }
}

到这里基本便实现了多数据源的配置和切换,可以通过@DataSource指定切换的数据源,没有注解的方法则走默认数据源。

测试

核心代码篇幅有点长,这里只放核心代码

public interface TestService {
    Test getTestInfo(int id);

	//指定数据源的测试方法
    Test getTestInfo2(int id);
}
@Service("testService")
public class TestServiceImpl implements TestService {

    @Autowired
    private TestDao testDao;

    @Override
    public Test getTestInfo(int id) {
        return testDao.selectByPrimaryKey(id);
    }

    @Override
    @DataSource(name = DataSourceDef.SECOND)
    public Test getTestInfo2(int id) {
        return testDao.selectByPrimaryKey(id);
    }
}

运行结果:

小结

以上便是”SpringBoot实现动态数据源配置和切换“的所有内容。如果您有什么疑问或者文章有什么问题,欢迎私信或留言交流~

猜你喜欢

转载自blog.csdn.net/hsf15768615284/article/details/104168955