【实战干货】SpringBoot整合多数据源

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介: 【实战干货】SpringBoot整合多数据源

image.png

文章大纲

🚐 一、前言

🚅 二、专栏推荐

🚔 三、整合多数据源需要了解的知识

🚢 四、SpringBoot+MyBatis整合多数据源

🔴 4.1 说明

🟠 4.2 涉及依赖包

🟡 4.3 项目配置

🟢 4.4 编写主副数据库数据源配置

🔵 4.5 执行结果

🟣 4.6 整合中遇到的问题

🚲 五、SpringBoot+Mybatis-Plus整合多数据源

🟥 5.1 说明

🟧 5.2 涉及的依赖包

🟨 5.3 相关配置

🟩 5.4 使用方式

🟦 5.5 执行结果

🚀 六、写在最后

image.png

🚐 一、前言


大家好,我是小诚,不知不觉上一次更文已经是20多天前了!其实这段时间也一直没有闲着,一个是在梳理之前的文章知识和资源,用于搭建技术圈子,另外一个就是在思考自己的一个输出方向,社区发展得很迅速,热榜各种各类的文章都有,深思熟虑后,还是坚持文章在精不在多,质量标准更加重要,所以今后博文的方向会更加偏向实战和经验,争取分享更加有价值的博文!


如果文章对你有帮助,可以帮忙一键三连和专栏订阅哦! 技术圈子经过这段时间的筹划,已经初步成型!有兴趣、志同道合的小伙伴可以查看左边导航栏的技术圈子介绍,期待你们的加入!


本篇文章重点介绍SpringBoot集合MyBatis和MyBatis-Plus整合多数据源方面的知识!

image.png

🚅 二、专栏推荐

  良心推荐: 下面的相关技术专栏还在免费分享哦,大家可以帮忙点点订阅哦!

  面试干货专栏

  常见开发问题专栏

  JAVA进阶知识专栏

  从0到1-全面深刻理解MySQL系列专栏

image.png

🚔 三、整合多数据源需要了解的知识


 1、何时会使用到多数据源


 一个技术的出现、应用必然是为了解决存在的某些问题,多数据源出现常见的场景如下:


 (1)、与第三方对接时,有些合作方并不会为了你的某些需求而给你开发一个功能,他们可以提供给你一个可以访问数据源的只读账号,你需要获取什么数据由你自己进行逻辑处理,这时候就避免不了需要进行多数据源整合了。


 (2)、业务数据达到了一个量级,使用单一数据库存储达到了一个瓶颈,需要进行分库分表等操作进行数据管理,在操作数据时,不可避免的涉及到多数据源问题。


 2、多数据源整合有哪些方式


 参考了网上的许多材料,发现整合方式无外乎以下几种:


 (1)、使用分包方式,不同的数据源配置不同的MapperScan和mapper文件


 (2)、使用APO切片方式,实现动态数据源切换(如果对Aop不是很熟悉,欢迎查看我之前的一篇文章,这知识保熟哦!【什么是面向切面编程?】)


 (3)、使用数据库代理中间件,如Mycat等


 3、不同方式之间的区别


 (1)、分包方式可以集合JTA(JAVA Transactional API)实现分布式事务,但是整个流程的实现相对来说比较复杂。


 (2)、AOP动态配置数据源方式缺点在于无法实现全局分布式事务,所以如果只是对接第三方数据源,不涉及到需要保证分布式事务的话,是可以作为一种选择。


 (3)、使用数据库代理中间件方式是现在比较流行的一种方式,很多大厂也是使用这种方式,开发者不需要关注太多与业务无关的问题,把它们都交给数据库代理中间件去处理,大量的通用的数据聚合,事务,数据源切换都由中间件来处理,中间件的性能与处理能力将直接决定应用的读写性能,比较常见的有Mycat、TDDL等。现在阿里出了100%自研的分布式数据库OceanBase,从最底层支持分布式,性能也非常强大,大家感兴趣的可以去了解下!


 4、本文实战选择的方式


 鉴于本次遇到需求的整合多数据源的场景是需要 对接第三方的数据,暂不涉及到分布式事务问题 ,所以本文实战整合多数据源使用的方式是【分包方式】实现简单的多数据源整合,至于其他方式和分布式事务的坑,后面再慢慢填吧(o(╥﹏╥)o)!

image.png

🚢 四、SpringBoot+MyBatis整合多数据源

🔴 4.1 说明

  本次案例涉及到的代码比较多,因此文章只贴出部分,全部案例代码已经上传到Gitee,需要者可直接访问:【SpringBoot结合MyBatis整合多数据源】,项目结构如下:

image.png

🟠 4.2 涉及依赖包

image.png

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.0</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.4.5</version>
        </dependency>

🟡 4.3 项目配置

# 项目启动端口
server:
  port: 9090
# 项目 名称
spring:
  application:
    name: multi-datasource-instance
  datasource:
    # 主数据库
    master:
      # 注意,整合多数据源时如果使用springboot默认的数据库连接池Hikari,指定连接数据使用的是jdbc-url而不是url属性
      jdbc-url: jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
      username: root
      password: 123456
      driver-class-name: com.mysql.cj.jdbc.Driver
    # 副数据库
    slave:
      # 注意,整合多数据源时如果使用springboot默认的数据库连接池Hikari,指定连接数据使用的是jdbc-url而不是url属性
      jdbc-url: jdbc:mysql://localhost:3306/test2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
      username: root
      password: 123456
      driver-class-name: com.mysql.cj.jdbc.Driver

🟢 4.4 编写主副数据库数据源配置

  1、主数据源相关配置:主要是指定主数据源、扫描的mapper地址、事务管理器等信息。

@Configuration
// 指定主数据库扫描对应的Mapper文件,生成代理对象
@MapperScan(basePackages ="com.diary.it.multi.datasource.mapper" ,sqlSessionFactoryRef = "masterSqlSessionFactory")
public class MasterDataSourceConfig {
    // mapper.xml所在地址
    private static final String MAPPER_LOCATION = "classpath*:mapper/*.xml";
    /**
     * 主数据源,Primary注解必须增加,它表示该数据源为默认数据源
     * 项目中还可能存在其他的数据源,如获取时不指定名称,则默认获取这个数据源,如果不添加,则启动时候回报错
     */
    @Primary
    @Bean(name = "masterDataSource")
    // 读取spring.datasource.master前缀的配置文件映射成对应的配置对象
    @ConfigurationProperties(prefix = "spring.datasource.master")
    public DataSource dataSource() {
        DataSource build = DataSourceBuilder.create().build();
        return build;
    }
    /**
     * 事务管理器,Primary注解作用同上
     */
    @Bean(name = "masterTransactionManager")
    @Primary
    public PlatformTransactionManager dataSourceTransactionManager(@Qualifier("masterDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    /**
     * session工厂,Primary注解作用同上
     */
    @Bean(name = "masterSqlSessionFactory")
    @Primary
    public SqlSessionFactory sqlSessionFactory(@Qualifier("masterDataSource") DataSource dataSource) throws Exception {
        final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MasterDataSourceConfig.MAPPER_LOCATION));
        return sessionFactoryBean.getObject();
    }
}

2、副数据源相关配置:主要是指定数据源、扫描的mapper地址、事务管理器等信息。

@Configuration
// 指定从数据库扫描对应的Mapper文件,生成代理对象
@MapperScan(basePackages = "com.diary.it.multi.datasource.mapper2", sqlSessionFactoryRef = "slaveSqlSessionFactory")
public class SlaveDataSourceConfig {
    // mapper.xml所在地址
    private static final String MAPPER_LOCATION = "classpath*:mapper2/*.xml";
    /**
     * 数据源
     */
    @Bean(name = "slaveDataSource")
    // 读取spring.datasource.slave前缀的配置文件映射成对应的配置对象
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DataSource dataSource() {
        DataSource build = DataSourceBuilder.create().build();
        return build;
    }
    /**
     * 事务管理器
     */
    @Bean(name = "slaveTransactionManager")
    public PlatformTransactionManager dataSourceTransactionManager(@Qualifier("slaveDataSource") DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
    /**
     * session工厂
     */
    @Bean(name = "slaveSqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory(@Qualifier("slaveDataSource") DataSource dataSource) throws Exception {
        final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(dataSource);
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(SlaveDataSourceConfig.MAPPER_LOCATION));
        return sessionFactoryBean.getObject();
    }
}

🔵 4.5 执行结果


  完成上面的步骤后,就跟我们平常写业务逻辑的方式一样,在service中写业务逻辑,在mapper中写sql语句等,下面看看执行结果!

image.png

🟣 4.6 整合中遇到的问题


 看完上面的教程,是不是发现其实整合多数据源其实也挺简单的!但是,完全按照教学流程整合还是遇到各种问题的现象真的太常见了,下面博主就总结下整合中遇到的各种问题,如果你在整合过程中也遇到了,可以直接按照博主的解决方案来哦(贴心吧!)。


 问题1、出现 jdbcUrl is required with driverClassName异常


 原因: SpringBoot2.x后默认的数据库连接池就是HikariCP(号称史上最快,性能最高),HikariCP连接池中命名规则和其他的连接池不太一样,指定连接数据库的地址时,它使用的是jdbc-url而不是url,所以如果我们不指定数据库连接池如druid而使用springboot默认的连接池的话,需要将配置中连接数据库的url改成jdbc-url属性。


 问题2、 出现 Invalid bound statement (not found)异常


 原因:


   (1)、在定义数据源配置信息时没有指定SqlSessionFactoryBean扫描的mapper.xml文件的位置即 sessionFactoryBean.setMapperLocations(xxx)。


   (2)、mapper.xml文件中namespace属性对应的路径不准确或者对应方法的id名称、parameterType属性不对


   (3)、xxxMapper.java的方法返回值是List,而select元素没有正确配置ResultMap,或者只配置ResultType


 问题3、 出现 required a single bean, but 2 were found异常


 原因: 因为我们在指定主副数据源配置时已经使用MapperScan注解进行扫描对应的mapper.java,此时被扫描到的mapper.java已经生成代理类到Spring容器,如果此时在启动类中再使用MapperScan扫描则会成出现上面的问题(奇怪的是:这个问题我换一台电脑就不报错了,所以出现这个问题先按照这个方案解决吧)


 问题4、 主数据源配置类中为什么添加Primary注解


 原因: 因为整合了多数据源,所以DataSource、PlatformTransactionManager等实例都会注入多个到Spring容器中,Primary注解的作用就是:当我们使用自动配置的方式如Autowired注入Bean时,如果这个Bean有多个候选者,如果其中一个候选者具有@Primary注解修饰,该候选者会被选中,作为自动配置的值。


 问题5、 com.mysql.jdbc.Driver 和 com.mysql.cj.jdbc.Driver的区别


 原因: 细心的小伙伴会发现,在数据库配置中driver-class-name属性的值为com.mysql.cj.jdbc.Driver,其实com.mysql.jdbc.Driver 是 对应mysql-connector-java 5驱动的,com.mysql.cj.jdbc.Driver 是 mysql-connector-java 6及之后的数据库驱动的,如果使用了6.x后的mysql数据库驱动还继续使用com.mysql.jdbc.Driver 则启动时会报deprecated(过时的),同时使用mysql6.x后的驱动需要指定时区serverTimezone:

image.png

🚲 五、SpringBoot+Mybatis-Plus整合多数据源


 上面Mybatis使用分包的方式整合多数据源多少还是有些麻烦的,但是使用MyBatis-Plus就比较简单了,MyBatis-Plus官方就支持了多数据源,使用的时候只需要一个注解就可以实现,整合多数据源的时候推荐使用该种方式。



🟥 5.1 说明


 本次案例涉及到的代码比较多,因此文章只贴出部分,全部案例代码已经上传到Gitee,需要者可直接访问:【实战-SpringBoot结合MyBatis-Plus整合多数据源】,mybatis-plus多数据源支持:

image.png

项目结构如下:

image.png

🟧 5.2 涉及的依赖包

image.png

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.4.5</version>
        </dependency>

🟨 5.3 相关配置

# 启动端口
server:
  port: 9091
# 项目名称
spring:
  application:
    name: multi-datasource-instance2
  datasource:
    # 采用动态选取
    dynamic:
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      datasource:
        # 主数据库
        master:
          url: jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver
        # 副数据库
        slave:
          url: jdbc:mysql://localhost:3306/test2?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8&useSSL=false
          username: root
          password: 123456
          driver-class-name: com.mysql.cj.jdbc.Driver

🟩 5.4 使用方式

image.png

🟦 5.5 执行结果

image.png

🚀 六、写在最后


 文章中所有代码都已上传到Gitee,有需要可以自取(后面会传到CSDN免费下载),如果有帮助不要忘了star哦,后面会有更多实战文章(顺便透露下下篇文章是:关于Ftp文件上传到服务器和下载到本地的实战),Gitee项目直通车如下:


 1、SpringBoot+MyBatis整合多数据源


 2、SpringBoot+MyBatis-Plus整合多数据源


 最近这段时间一直忙着整理技术圈子资源,所以更文比较少,现在技术圈子资源已经初步整理完毕,后面会陆续恢复更文速度。【技术圈子】中有免费面试资源、简历模板、年终汇报PPT、CSDN VIP下载资源等等,感兴趣者可以扫描下面二维码或者查看左边导航栏进入技术圈子。期待您的加入!【不是一个人的圈子,而是技术人的圈子】


相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
6月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1052 3
|
4月前
|
监控 Cloud Native Java
Spring Boot 3.x 微服务架构实战指南
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Spring Boot 3.x与微服务架构,探索云原生、性能优化与高可用系统设计。以代码为笔,在二进制星河中谱写极客诗篇。关注我,共赴技术星辰大海!(238字)
Spring Boot 3.x 微服务架构实战指南
|
5月前
|
消息中间件 Ubuntu Java
SpringBoot整合MQTT实战:基于EMQX实现双向设备通信
本教程指导在Ubuntu上部署EMQX 5.9.0并集成Spring Boot实现MQTT双向通信,涵盖服务器搭建、客户端配置及生产实践,助您快速构建企业级物联网消息系统。
2076 1
|
11月前
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
1030 79
|
9月前
|
监控 Java 调度
SpringBoot中@Scheduled和Quartz的区别是什么?分布式定时任务框架选型实战
本文对比分析了SpringBoot中的`@Scheduled`与Quartz定时任务框架。`@Scheduled`轻量易用,适合单机简单场景,但存在多实例重复执行、无持久化等缺陷;Quartz功能强大,支持分布式调度、任务持久化、动态调整和失败重试,适用于复杂企业级需求。文章通过特性对比、代码示例及常见问题解答,帮助开发者理解两者差异,合理选择方案。记住口诀:单机简单用注解,多节点上Quartz;若是任务要可靠,持久化配置不能少。
831 4
|
10月前
|
缓存 安全 Java
深入解析HTTP请求方法:Spring Boot实战与最佳实践
这篇博客结合了HTTP规范、Spring Boot实现和实际工程经验,通过代码示例、对比表格和架构图等方式,系统性地讲解了不同HTTP方法的应用场景和最佳实践。
946 5
|
12月前
|
Java Spring
SpringBoot 实战 不同参数调用不同实现
本文介绍了如何在实际工作中根据不同的入参调用不同的实现,采用`map+enum`的方式实现优雅且严谨的解决方案。通过Spring Boot框架中的工厂模式或策略模式,避免了使用冗长的`if...else...`语句。文中详细展示了定义接口、实现类、枚举类以及控制器调用的代码示例,确保用户输入的合法性并简化了代码逻辑。
451 1
SpringBoot 实战 不同参数调用不同实现
|
12月前
|
JavaScript 前端开发 Java
Jeesite5:Star24k,Spring Boot 3.3+Vue3实战开源项目,架构深度拆解!让企业级项目开发效率提升300%的秘密武器
Jeesite5 是一个基于 Spring Boot 3.3 和 Vue3 的企业级快速开发平台,集成了众多优秀开源项目,如 MyBatis Plus、Bootstrap、JQuery 等。它提供了模块化设计、权限管理、多数据库支持、代码生成器和国际化等功能,极大地提高了企业级项目的开发效率。Jeesite5 广泛应用于企业管理系统、电商平台、客户关系管理和知识管理等领域。通过其强大的功能和灵活性,Jeesite5 成为了企业级开发的首选框架之一。访问 [Gitee 页面](https://gitee.com/thinkgem/jeesite5) 获取更多信息。
667 0
Jeesite5:Star24k,Spring Boot 3.3+Vue3实战开源项目,架构深度拆解!让企业级项目开发效率提升300%的秘密武器
|
Java 数据库连接
SpringBoot配置多数据源实战
第四届光学与机器视觉国际学术会议(ICOMV 2025) 2025 4th International Conference on Optics and Machine Vision
743 8
|
自然语言处理 Java API
Spring Boot 接入大模型实战:通义千问赋能智能应用快速构建
【10月更文挑战第23天】在人工智能(AI)技术飞速发展的今天,大模型如通义千问(阿里云推出的生成式对话引擎)等已成为推动智能应用创新的重要力量。然而,对于许多开发者而言,如何高效、便捷地接入这些大模型并构建出功能丰富的智能应用仍是一个挑战。
3076 6