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));

 

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