微服务架构盛行的今天,应用服务与数据库的对应关系通常是一个微服务对应一个数据库。

在一个电商系统中,用户信息存储在用户数据库中,订单信息存储在订单数据库中,如果一次请求需要获取订单相关信息,则需要将订单信息和下单的用户信息一同查询出来。

在订单服务中获取用户数据不会直接调用用户数据库,而是通过调用用户管理服务的接口。

这种架构在大型系统中优势很明显,在业务上可以解耦,避免一个服务对用多个数据库,导致业务混乱,系统维护困难。也可以提高数据库的安全性。

应用场景

然而在些B端的管理系统,架构通常没有这么复杂(单体架构),只有一个服务。
这种应用也有连接多个数据库的需求,例如同步数据库。

Spring Boot 连接数据库默认配置

这里使用Spring Boot 和 Mybatis 。

由于Spring boot 的易用性,默认情况下,我们只需要在application配置文件中,

  • 配置好数据源的信息
  • Mybtis的Mapper扫描路径,
  • 以及在Configuration类中配置MapperScan配置对应Mapper类的包路径
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db1?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
    username: root
    password:  12345
mybatis: 
  mapper-locations: /mapper/**.xml
@SpringBootApplication
@MapperScan("icu.daydream.demo.mybatisdemo.mapper")
public class MybatisDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(MybatisDemoApplication.class, args);
    }

}

完成以上三个配置,不需要再创建 DataSource 对象,以及 SqlSessionFactory 对象,即可使应用自动连接上数据库。体现了Spring Boot 约定大于配置 的特性。

在Spring Boot 中应用中如何同时连接多个数据库呢?

现在我们的需求是同时连接两个数据库,Spring Boot 的默认配置已经满足不了需求,因此就需要手动的去配置数据源信息。

在application.yaml中配置两个自定义的数据源属性

创建 DataSource 对象和 SqlSessionFactory 对象

先创建连接数据库1的 需要的对象。

@Configuration
@MapperScan(basePackages = DataSourceConfig1.PACKAGE,sqlSessionFactoryRef = "sqlSessionFactory1")
public class DataSourceConfig1 {
    //数据库1 扫描的Mapper类路径
    final static String PACKAGE = "test.mapper.db1";

    @Bean(name = "dataSource1")
    //将yaml文件中的 datasource1 下的属性 注入到 DataSource对象中
    @ConfigurationProperties(prefix = "datasource1")
    public DataSource businessDbDataSource() {
        return new DruidDataSource();
    }

    @Bean(name = "sqlSessionFactory1")
    public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource1") DataSource dataSource ) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource ); 
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/db1/*.xml"));
        return factoryBean.getObject();
    }
    
} 
默认配置下这两个 Bean 对象是自动创建的,现在显式创建后,Spring Boot 的默认配置对象就不会再创建了, application.yaml 中mybatis下的一些配置也跟着失效了。需要显式创建 Myabtis 的 Configuration 配置对象。这个后面再讲。

目前已经配置好了数据库1的连接,同样地,再创建一个连接数据库2的对象。

@Configuration
@MapperScan(basePackages = DataSourceConfig2.PACKAGE,sqlSessionFactoryRef = "sqlSessionFactory2")
public class DataSourceConfig2 {
    //数据库1 扫描的Mapper类路径
    final static String PACKAGE = "test.mapper.db2";

    @Bean(name = "dataSource2")
    //将yaml文件中的 datasource1 下的属性 注入到 DataSource对象中
    @ConfigurationProperties(prefix = "datasource2")
    public DataSource businessDbDataSource() {
        return new DruidDataSource();
    }

    @Bean(name = "sqlSessionFactory2")
    public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource2") DataSource dataSource ) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dataSource );
        factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/db2/*.xml"));
        return factoryBean.getObject();
    } 
} 

包结构如下:

以上多数据源就配置完成了,db1下的mapper查询会连接数据库1,db2下的mapper连接数据库2 .

注解说明

  • @Bean:在@Configuration类中使用, 作用在方法上,方法的返回值为 创建 Bean对象,并注入到 Spring 容器中。属性name 为 Bean对象的名称,不加则方法名为Bean对象名称。
  • @MapperScan:用于扫描Mapper对象的包路径
  • @Qualifier:作用在方法参数上,根据Bean对象名称注入Bean对象

Mybatis 显示配置数据源,application的mybatis相关配置失效

在配置连个数据源后,application中 mybatis下的相关配置失效了。例如将SQL查询的字段名从下划线转为小驼峰,通常在application中这么配置:

mybatis:
  configuration:
    map-underscore-to-camel-case: true

在创建多个数据源后,该配置失效了,因为Mybatis 中的 Configuration 没有被创建,在多个数据源的情况下, Mybatis也不知道要将该配置配置在哪个数据源下。

因此需要手动创建 Configuration Bean对象,并注入到 SqlSessionFactoryBean对象中。

①创建Bean对象

@Bean("customSessionConfiguration")
@ConfigurationProperties(prefix = "mybatis.configuration")
public org.apache.ibatis.session.Configuration configuration(){
    return new org.apache.ibatis.session.Configuration();
}

② 更改 sqlSessionFactory1 的方法,将Configuration 对象注入进去

@Bean(name = "sqlSessionFactory1")
public SqlSessionFactory sqlSessionFactory1(@Qualifier("dataSource1") DataSource dataSource , @Qualifier("customSessionConfiguration") org.apache.ibatis.session.Configuration configuration) throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource );
    factoryBean.setConfiguration(configuration);
    factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
            .getResources("classpath:mapper/db1/*.xml"));
    return factoryBean.getObject();
} 

如果觉得文章对你有帮助,就请作者喝杯Java吧!我是白日梦。


daydream
1 声望0 粉丝