SpringBoot+MybatisPlus整合多數據源(踩坑指南)

一、配置perproties/yml文件

(1)不同數據庫的配置信息

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
#spring.datasource.tomcat= com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql://localhost:3306/paidan_data_upload?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.maximum-pool-size=15
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.idle-timeout=300000
spring.datasource.hikari.pool-name=DatebookHikariCP
spring.datasource.hikari.max-lifetime=1800000
spring.datasource.hikari.connection-timeout=300000

#spring.datasource.slave.poolName=slave
spring.datasource.slave.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.slave.url=jdbc:mysql://localhost:3306/paidan_data_upload2?characterEncoding=utf8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
spring.datasource.slave.username=root
spring.datasource.slave.password=123456
spring.datasource.slave.hikari.minimum-idle=5
spring.datasource.slave.hikari.maximum-pool-size=15
spring.datasource.slave.hikari.auto-commit=true
spring.datasource.slave.hikari.idle-timeout=300000
spring.datasource.slave.hikari.pool-name=DatebookHikariCP
spring.datasource.slave.hikari.max-lifetime=1800000
spring.datasource.slave.hikari.connection-timeout=300000


mybatis-plus.mapper-locations=classpath:/mapper/*Mapper.xml
#實體掃描,多個package用逗號或者分號分隔
mybatis-plus.typeAliasesPackage=com.chinadep.*.dataroute.bean,com.chinadep.*.mapper
mybatis-plus.global-config.id-type=3
mybatis-plus.global-config.field-strategy=2
mybatis-plus.global-config.db-column-underline=true
mybatis-plus.global-config.capital-mode=true
mybatis-plus.configuration.lazy-loading-enabled=false
mybatis-plus.configuration.aggressive-lazy-loading=false
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.cache-enabled=false
mybatis-plus.configuration.jdbc-type-for-null=null

二、一些配置文件

(1)DatabaseType(不同數據庫的名字標誌(可以任意填寫))

public enum DatabaseType {
    dataBase1,
    dataBase2
}

(2)DynamicDataSource(動態數據源(需要繼承AbstractRoutingDataSource))

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        //使用DatabaseContextHolder獲取當前線程的DatabaseType
        return DatabaseContextHolder.getDatabaseType();
    }

}

(3)DatabaseContextHolder(保存一個線程安全的DatabaseType容器)

public class DatabaseContextHolder {

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

    public static void setDatabaseType(DatabaseType type) {
        contextHolder.set(type);
    }

    public static DatabaseType getDatabaseType() {
        return contextHolder.get();
    }
}
(4)Mybatisplus配置
@Configuration
public class MybatisPlusConfig {

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor page = new PaginationInterceptor();
        //設置方言
        page.setDialectType("mysql");
        return page;
    }

    /**
     * sql性能分析插件
     */
    @Bean
    public PerformanceInterceptor performanceInterceptor() {
        return new PerformanceInterceptor().setFormat(false);
    }

    /**
     * 執行分析插件
     */
    @Bean
    public SqlExplainInterceptor sqlExplainInterceptor() {
        SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor();
        sqlExplainInterceptor.setStopProceed(false);
        return sqlExplainInterceptor;
    }

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

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

    /**
     * Primary 該註解表示在同一個接口有多個實現類可以注入的時候,默認選擇哪一個,而不是讓@autowire註解報錯
     * Qualifier 根據名稱進行注入,通常是在具有相同的多個類型的實例的一個注入(例如有多個DataSource類型的實例)
     */
    @Bean
    @Primary
    public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
                                        @Qualifier("slaveDataSource") DataSource slaveDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DatabaseType.dataBase1, masterDataSource);
        targetDataSources.put(DatabaseType.dataBase2, slaveDataSource);
        DynamicDataSource dataSource = new DynamicDataSource();
        // 該方法是AbstractRoutingDataSource的方法
        dataSource.setTargetDataSources(targetDataSources);
        // 默認的datasource設置爲myTestDbDataSource
        dataSource.setDefaultTargetDataSource(masterDataSource);
        return dataSource;
    }

    @Bean
    public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDataSource") DataSource masterDataSource,
                                               @Qualifier("slaveDataSource") DataSource slaveDataSource) throws Exception {
        MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean =new MybatisSqlSessionFactoryBean();
        mybatisSqlSessionFactoryBean.setDataSource(this.dataSource(masterDataSource, slaveDataSource));
        return mybatisSqlSessionFactoryBean.getObject();
    }

    /**
     * 配置事務管理器
     */
    @Bean
    public DataSourceTransactionManager transactionManager(DynamicDataSource dataSource) throws Exception {
        return new DataSourceTransactionManager(dataSource);
    }



}

(5)使用

 @GetMapping(value = "/test")
    public void saveTestServerUrl() {
        List<ServerUrl> serverUrlRestult = serverUrlDao.selectList(new EntityWrapper<>());
        System.out.println(serverUrlRestult);
        DatabaseContextHolder.setDatabaseType(DatabaseType.dataBase2);
        List<ServerUrl> serverUrlRestult1 = serverUrlDao.selectList(new EntityWrapper<>());
        System.out.println(serverUrlRestult1);
    }

三、注意(踩坑)

(1)之前按照整合mybatis多數據源的方式去整合mybatisplus,項目正常啓動,但是當請求db的時候,出現org.apache.ibatis.binding.BindingException: Invalid bound statement not found 錯誤。當時想的是mybatisplus和mybatis是向下兼容的,配置的方式應該是一樣的。然後事實並非如此,出現這個問題之後,就猜想是不是缺少哪些配置,導致mybatisplus掃描不到自己封裝的xml文件(調用的是plus自帶的方法,沒有自定義xml文件)。之後嘗試過各種mapperscan,無濟於事。。。。

先說明,原理還沒搞懂。大概原因是,MybatisPlus需要用自己的 MybatisSqlSessionFactoryBean,用SqlSessionFactory 可能有問題。

(2)解決方案:

將mybatisplus配置sqlSessionFactory改成MybatisSqlSessionFactoryBean。問題解決
 

        MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean =new MybatisSqlSessionFactoryBean();
        mybatisSqlSessionFactoryBean.setDataSource(this.dataSource(masterDataSource, slaveDataSource));

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章