SpringBoot MyBatyisPlus 多數據源切換

  • 實現功能爲通 aop 控制不同包下面的類採用不同的數據庫
    • mapper.one 包中的數據庫採用 one_db
    • mapper.two 包總的數據庫採用 two_db

導入相關依賴

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.21</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

在配置文件中配置數據源

##onedb
spring.datasource.druid.one.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.one.url=jdbc:mysql://localhost:3306/db_one?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.one.username=username
spring.datasource.druid.one.password=password

##twodb
spring.datasource.druid.two.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.two.url=jdbc:mysql://localhost:3306/db_two?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.druid.two.username=username
spring.datasource.druid.two.password=password

配置 MyBatisPlus 相關

mybatis-plus:
  mapper-locations: classpath:/mapper/**/*Mapper.xml
  typeAliasesPackage: com.sec.datasource.*.domain
  global-config:
    refresh:  true
    db-config:
      id-type: auto
      field-strategy: ignored
      capital-mode: true
      logic-delete-value: 1
      logic-not-delete-value: 0
      db-type: mysql
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
    jdbc-type-for-null: 'null'

config 包下配置 MyBatisPlus 數據源

@Configuration
@MapperScan("com.sec.datasource.datasource.mapper")
public class MyBatiesPlusConfiguration {

    @Bean(name = "one")
    @ConfigurationProperties(prefix = "spring.datasource.druid.one" )
    public DataSource one() {
        return DruidDataSourceBuilder.create().build();
    }

    @Bean(name = "two")
    @ConfigurationProperties(prefix = "spring.datasource.druid.two" )
    public DataSource two() {
        return DruidDataSourceBuilder.create().build();
    }

    /**
     * 動態數據源配置
     * @return
     */
    @Bean
    @Primary
    public DataSource multipleDataSource(@Qualifier("one") DataSource onedb, @Qualifier("two") DataSource twodb) {
        MultipleDataSource multipleDataSource = new MultipleDataSource();
        Map< Object, Object > targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceEnum.ONE_DB.getValue(), onedb);
        targetDataSources.put(DataSourceEnum.TWO_DB.getValue(), twodb);
        //添加數據源
        multipleDataSource.setTargetDataSources(targetDataSources);
        //設置默認數據源
        multipleDataSource.setDefaultTargetDataSource(onedb);
        return multipleDataSource;
    }

    @Bean("sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(multipleDataSource(one(), two()));

        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setJdbcTypeForNull(JdbcType.NULL);
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setCacheEnabled(false);
        sqlSessionFactory.setConfiguration(configuration);
        return sqlSessionFactory.getObject();
    }

}

其他輔助類

public class DataSourceContextHolder {

    private static final ThreadLocal<String> contextHolder = new InheritableThreadLocal<>();

    public static void setDataSource(DataSourceEnum db){
        contextHolder.set(db.getValue());
    }

    public static String getDataSource(){
        return contextHolder.get();
    }

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

}
public class MultipleDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }

}

將已有數據庫定義成枚舉方便調用

@Getter
public enum DataSourceEnum {

    ONE_DB("one_db"),
    TWO_DB("two_db");

    private String value;

    DataSourceEnum(String value){this.value=value;}

}

編寫 aop 邏輯進行數據源切換

@Slf4j
@Aspect
@Order(-1)
@Component
public class DataSourceAspect {

    @Pointcut("execution(* com.sec.datasource.datasource.mapper.onedb.*.*(..))")
    private void onedbAspect() {
    }

    @Pointcut("execution(* com.sec.datasource.datasource.mapper.twodb.*.*(..))")
    private void twodbAspect() {
    }

    @Before("onedbAspect()")
    public void onedb() {
        log.info("select to datasource one");
        DataSourceContextHolder.setDataSource(DataSourceEnum.ONE_DB);
    }

    @Before("twodbAspect()")
    public void twodb() {
        log.info("select to datasource two");
        DataSourceContextHolder.setDataSource(DataSourceEnum.TWO_DB);
    }

    @After("onedbAspect() || twodbAspect()")
    public void doAfter(){
        DataSourceContextHolder.clear();
    }

}
下面就是在 mapper 包中編寫邏輯 controller 調用測試了

在這裏插入圖片描述

Demo 在我的 Gitee 中可以看得到
https://gitee.com/jiangruyi/many-datasource.git

發佈了52 篇原創文章 · 獲贊 41 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章