Spring Boot多数据源配置详解及报错问题解决
作者:mmseoamin日期:2023-12-11

Spring Boot多数据源配置详解

前几天,公司提了个需求,对一个项目进行二次开发,在开发过程中,需要配置多数据源来进行数据库的操作。下面我将主键探索总结的配置流程和遇到的各种坑做以总结,希望能够帮到遇到同样问题的友友。有错的地方,请各位大佬留言指出。

1.双数据源配置

首先是数据源配置:application.yml文件,这里要注意的是单数据源下的数据库路径为url,多数据源下为jdbc-url

spring:
#单数据源
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    jdbc-url: jdbc:mysql://127.0.0.1:3306/meeting?serverTimezone=UTC
    username: root
    password: 1111
# 多数据源
  datasource:
    one: #数据源1的配置
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://127.0.0.1:3306/meeting?serverTimezone=UTC
      username: root
      password: 1111
    two:  #数据源2的配置
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://127.0.0.1:3306/xin-master?serverTimezone=UTC
      username: root
      password: 1111

注意点:当我们使用多数据源配置的时候,mybatis和plus的配置就不需要在.yml文件中配置了,下面就是关于数据源的一些其他config配置了。

2.当数据源配置好之后,就需要注意我们的项目结构了,由于是两套数据源,所以对应的mapper和xml文件应当放在不同的包或者目录下

Spring Boot多数据源配置详解及报错问题解决,在这里插入图片描述,第1张

将每个数据源对应的mapper接口,和*Mapper.xml文件分开放在不同的包下,保证在进行数据库的装配时,根据我们的不同包,对应好不同的数据源。

3.对不同的数据源进行不同的配置

数据源在配置时候要有主从之分,这里我的one数据源为主库,他的配置如下,代码过程请仔细看,主库和从库配置略有不同


> “主库配置如下”


@Configuration
> 这里进行mapper接口路径的扫描
@MapperScan(basePackages = "com.sbp.api.mapper.mapper1", sqlSessionTemplateRef = "db1SqlSessionTemplate")
public class DataSourceOneConfig {
> 这里是一个不同点,主库要加"@Primary"注解
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.one")
    @Primary
    public DataSource db1DataSource() {
        return DataSourceBuilder.create().build();
    }
> 这里是一个不同点,主库要加"@Primary"注解
    @Bean
    @Primary
    @Lazy  //这个是懒加载的注解,根据自己项目需要看是否添加 
    public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //开启驼峰
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        > "这个方法的调用是指定当前数据源的mybatis的Xml文件的路径"
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapping/mapper1/*.xml"));
        return bean.getObject();
    }
    @Bean
    @Primary
    public DataSourceTransactionManager db1TransactionManager(@Qualifier("db1DataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    @Bean
    @Primary
    @Lazy
    public SqlSessionTemplate db1SqlSessionTemplate(@Qualifier("db1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

从库配置如下


和主库配置基本相同,只不过主库的每个Bean前要加"@Primary"注解,从库不加。

@Configuration
@MapperScan(basePackages = "com.sbp.api.mapper.mapper2", sqlSessionTemplateRef = "sqlSessionTemplate2")
public class DataSourceTwoConfig {
    @Bean(name = "dataSource2")
    @ConfigurationProperties(prefix = "spring.datasource.two")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }
    @Bean(name = "sqlSessionFactory2")
    public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //开启驼峰
        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapping/mapper2/*.xml"));
        return bean.getObject();
    }
    @Bean(name = "transactionManager2")
    public DataSourceTransactionManager transactionManager(@Qualifier("dataSource2") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    @Bean(name = "sqlSessionTemplate2")
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
}

将上面的内容配置好之后,基本就完成了双数据源的配置,但是为了项目的健康运行,还需要检查下面的一些配置:

1.项目主启动类是否添加了@MapperScan(“*”)注解,如果添加了,请将他去掉,因为我们的每个数据源在config配置类中都单独指定了basePackages 扫描路径。这里再添加上可能会报错。因为我再测试过程中遇到了。

2.项目启动后主库访问可能没有问题,但是从库访问报:Invalid bound statement (not found):com…selectAll这种错误

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.hnchances.api.mapper.mapper2.ymssm.YmSsmMapper.insterPhone

网上解决办法我找着都试了一遍,好多大佬都有遇到这种问题,提供的问题解决思路如下

通常导致这种原因的大致有以下这几种情况

1、mapper的namespace 有问题

2、 xxMapper的方法在xxMapper.xml中没有,调用那个方法就报错

3、没有正确配置ResultMap,或者只配置ResultType!等等。

当筛选完毕上边这些配置都没有问题,那么就要考虑是不是mybatis或者mybatis-plus自动加载了mapper,导致我们再配置类中手动配置的xml路径失效,导致的 Invalid bound statement (not found)问题。

需要将二者的自动加载排除:在主启动类中进行排除即可:

> "这里@SpringBootApplication中的语句就是排除二者的自动mapper加载,如果你的项目中只有其中一个依赖的话,就只需要排除一个就行,"
> "我的项目在之前开发时,他们两个mybatis持久层框架都使用了,所以两个都需要排除"
@SpringBootApplication(exclude = {MybatisAutoConfiguration.class, MybatisPlusAutoConfiguration.class})
// 开启定时任务
@EnableScheduling
//@MapperScan("com.hnchances.api.mapper")  //多数据源,这里不需要包扫描
@Import({DataSourceOneConfig.class, DataSourceTwoConfig.class})
public class ApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(ApiApplication.class, args);
    }
}

至此,spring boot多数据源配置和遇坑报错问题基本都解决了,如果友友们还遇到其他问题,并且找到了解决思路的话,欢迎留下文章链接供大家参考。