实战指南,SpringBoot + Mybatis 如何对接多数据源
作者:mmseoamin日期:2023-12-11

系列文章目录

MyBatis缓存原理

Mybatis plugin 的使用及原理

MyBatis+Springboot 启动到SQL执行全流程

数据库操作不再困难,MyBatis动态Sql标签解析

从零开始,手把手教你搭建Spring Boot后台工程并说明

Spring框架与SpringBoot的关联与区别

Spring监听器用法与原理详解

Spring事务畅谈 —— 由浅入深彻底弄懂 @Transactional注解


实战指南,SpringBoot + Mybatis 如何对接多数据源

  • 系列文章目录
  • 一、数据源的定义
  • 二、单数据源配置
  • 三、如何配置多数据源
    • 1. 工程层级调整
    • 2. Spring项目配置
    • 3. 会话配置
    • 4. 事务管理器
    • 四、验证
    • 总结

      实战指南,SpringBoot + Mybatis 如何对接多数据源,在这里插入图片描述,第1张

      在我们开发一些具有综合功能的项目时,往往会碰到一种情况,需要同时连接多个数据库,这个时候就需要用到多数据源的设计。而Spring 与 Myabtis 其实做了多数据源的适配,只需少许改动即可对接多数据源。本期我们就贴近实战,以一个单数据源的Demo为例,讲述将其改为多数据源项目的过程,希望大家能有所体会

      📕作者简介:战斧,从事金融IT行业,有着多年一线开发、架构经验;爱好广泛,乐于分享,致力于创作更多高质量内容

      📗本文收录于 Spring全家桶 专栏,有需要者,可直接订阅专栏实时获取更新

      📘高质量专栏 云原生、RabbitMQ、Spring全家桶 等仍在更新,欢迎指导

      📙Zookeeper Redis kafka docker netty等诸多框架,以及架构与分布式专题即将上线,敬请期待


      一、数据源的定义

      数据源(Data Source)是指数据存储的地方,大多数情况是指数据库,不过文件服务器、传感器、API等也能算数据源,主要是提供了对数据的访问和操作。数据源中存储了所有建立数据库连接的信息。就像通过指定文件名称可以在文件系统中找到文件一样,通过提供正确的数据源名称,你可以找到相应的数据库连接

      实战指南,SpringBoot + Mybatis 如何对接多数据源,在这里插入图片描述,第2张

      二、单数据源配置

      因为SpringBoot对数据源有着高度的默认配置,只配置一个数据源时,该数据源会被作为默认,所以对接单数据源其实是非常简单的。如果你的工程采用的yaml格式配置文件,我们仅需做如下配置:

      spring:
        #数据库连接配置
        datasource:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/springtest
          username: root
          password: root
      

      如果是采用properties配置文件的也是一样的:

      spring.datasource.driver-class-name=com.mysql.jdbc.Driver
      spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springtest
      spring.datasource.username=root
      spring.datasource.password=root
      

      三、如何配置多数据源

      1. 工程层级调整

      我们以曾经搭建的工程为原始模板,进行对接多数据源的操作。没看过的可以点此查看: 从零开始,手把手教你搭建Spring Boot后台工程并说明

      实战指南,SpringBoot + Mybatis 如何对接多数据源,在这里插入图片描述,第3张

      因为仅变动数据源,所以我们不改动其他层级,仅仅将 mapper 拆为 mapper1 与 mapper2 两部分

      实战指南,SpringBoot + Mybatis 如何对接多数据源,在这里插入图片描述,第4张

      2. Spring项目配置

      然后我们需要在 application.properties 或者 application.yml 中定义多个数据源:

      spring:
        #数据库连接配置
        datasource1:
          driver-class-name: com.mysql.cj.jdbc.Driver
          jdbc-url: jdbc:mysql://127.0.0.1:3306/springtest2
          username: root
          password: root
        datasource2:
          driver-class-name: com.mysql.cj.jdbc.Driver
          jdbc-url: jdbc:mysql://127.0.0.1:3306/springtest
          username: root
          password: root
      

      这里有两个细节需要注意:

      1. 因为我们决定使用双数据源,所以把数据源的连接配置改成了datasource1 和 datasource2。而不再保留datasource,这样SpringBoot就不再会为我们设定默认数据库
      2. 因为我们目前采用的 springBoot2.5.2,默认的连接池为Hikari,该连接池数据源的地址字段为jdbc-url 而非 url。在只有单个数据源时,SpringBoot走默认数据源逻辑为我们把 url 与 jdbc-url 进行映射,保证我们获得数据源。此时我们自己设置的数据源没有进行映射处理,就需要保证字段符合Hikari的要求。否则会出现 java.lang.IllegalArgumentException: jdbcUrl is required with driverClassName 异常

      3. 会话配置

      仅有配置文件可不行,接下来,我们需要在代码中读取到配置,并建立两个数据源。如下,每个数据源都有隔离的mapper接口、xml文件、会话工厂及会话模板

      第一个数据源 如下(示例):

      @Configuration
      @MapperScan(basePackages = "com.zhanfu.springboot.demo.mapper1", sqlSessionFactoryRef = "sqlSessionFactory1")
      public class DataSource1Config {
          @Bean
          @ConfigurationProperties(prefix = "spring.datasource1")
          public DataSource dataSource1() {
              return DataSourceBuilder.create().build();
          }
          @Bean
          public SqlSessionFactory sqlSessionFactory1() throws Exception {
              SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
              sessionFactoryBean.setDataSource(dataSource1());
              String locationPattern = "classpath*:/mapper1/*.xml";
              PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
              sessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern));
              return sessionFactoryBean.getObject();
          }
          @Bean(name = "sqlSessionTemplate1")
          public SqlSessionTemplate sqlSessionTemplate1(@Qualifier("sqlSessionFactory1") SqlSessionFactory sqlSessionFactory) {
              return new SqlSessionTemplate(sqlSessionFactory);
          }
      }
      

      配置第二个数据源 DataSource2Config

      @Configuration
      @MapperScan(basePackages = "com.zhanfu.springboot.demo.mapper2", sqlSessionFactoryRef = "sqlSessionFactory2")
      public class DataSource2Config {
          @Bean
          @ConfigurationProperties(prefix = "spring.datasource2")
          public DataSource dataSource2() {
              return DataSourceBuilder.create().build();
          }
          @Bean
          public SqlSessionFactory sqlSessionFactory2() throws Exception {
              SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
              sessionFactoryBean.setDataSource(dataSource2());
              String locationPattern = "classpath*:/mapper2/*.xml";
              PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
              sessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern));
              return sessionFactoryBean.getObject();
          }
          @Bean(name = "sqlSessionTemplate2")
          public SqlSessionTemplate sqlSessionTemplate2(@Qualifier("sqlSessionFactory2") SqlSessionFactory sqlSessionFactory) {
              return new SqlSessionTemplate(sqlSessionFactory);
          }
          @Bean(name = "productMapper")
          public ProductMapper mapper2(@Qualifier("sqlSessionTemplate2") SqlSessionTemplate sqlSessionTemplate) throws Exception {
              return sqlSessionTemplate.getMapper(ProductMapper.class);
          }
      }
      

      4. 事务管理器

      为两个数据源分别配置自己的事务管理器,如果你的项目里通篇没有方法级别的事务(一个SQL就是一个事务),那不设置这个也不影响,否则还是建议加上。

      @Configuration
      public class TransactionManagerConfig {
          @Autowired
          private DataSource dataSource1;
          @Autowired
          private DataSource dataSource2;
          @Bean
          public PlatformTransactionManager txManager1() {
              return new DataSourceTransactionManager(dataSource1);
          }
          @Bean
          public PlatformTransactionManager txManager2() {
              return new DataSourceTransactionManager(dataSource2);
          }
      }
      

      四、验证

      我们把两张表拆进两个库中,以两个库模拟两个数据源,使得程序可以同时连接两个库

      实战指南,SpringBoot + Mybatis 如何对接多数据源,在这里插入图片描述,第5张

      浏览器输入 http://127.0.0.1:8080/user/findall 查询接口成功

      实战指南,SpringBoot + Mybatis 如何对接多数据源,在这里插入图片描述,第6张

      再在浏览器输入 http://127.0.0.1:8080/product/findall 查询第二个库的数据亦成功返回

      实战指南,SpringBoot + Mybatis 如何对接多数据源,在这里插入图片描述,第7张

      这样我们就完成了一个工程同时连接两个数据源。


      总结

      经过上述的操作,我们已经成功把项目对接了多数据源。当然,方案肯定不止这一种,后续围绕该问题,我们还会讲解其他方式。但不论是什么方式,主旨都是加深大家对SpringBoot 和 Mybatis的理解,我们曾经梳理过全流程,但只是蜻蜓点水带大家看一遍大体轮廓,并不足以让你精通,后面本专栏将继续深入讲解