【Spring Boot】Spring Boot整合多数据源

文章目录

  • 前言
  • 一、基本概念
    • [1.1 什么是多数据源?](#1.1 什么是多数据源?)
    • [1.2 为什么要使用多数据源?](#1.2 为什么要使用多数据源?)
  • [二、如何在 Spring Boot 中整合多数据源?](#二、如何在 Spring Boot 中整合多数据源?)
    • [2.1 基本配置](#2.1 基本配置)
    • [2.2 项目代码](#2.2 项目代码)
    • [2.3 注意事项](#2.3 注意事项)

前言

在实际的开发工作中,我们经常会遇到需要整合多个数据源的情况,比如同时连接多个数据库、读写分离、跨数据库查询等。本文将介绍如何使用Spring Boot来实现多数据源的整合,对于刚刚接触开发的小伙伴可能有一些帮助。

一、基本概念

1.1 什么是多数据源?

在一个应用程序中使用多个数据源意味着我们需要在不同的数据源之间进行切换,以便从不同的数据源中获取数据。多数据源可以是关系数据库、NoSQL 数据库、平面文件、XML 文件等。在一个应用程序中使用多数据源的好处是,我们可以根据应用程序的需求选择最合适的数据源,从而提高应用程序的性能和可扩展性。

1.2 为什么要使用多数据源?

在一个应用程序中使用多数据源的好处有很多,其中一些是:

  • 可以根据应用程序的需求选择最合适的数据源,从而提高应用程序的性能和可扩展性。
  • 可以减少单一数据源所带来的风险,例如单点故障。
  • 可以更好地支持数据的隔离和数据的安全性。
  • 可以更好地支持不同的业务需求。

二、如何在 Spring Boot 中整合多数据源?

2.1 基本配置

接下来的整合示例,我将以实际项目整合示例来介绍,项目中是mysql和phoenix多数据源,那么接下来详细描述一下,因为项目中整合了MybatisPlus,所以也会有一些相关的配置,首先,我们需要在pom.xml文件中添加相应的依赖项。以下是常用的数据源依赖项:

xml 复制代码
<!-- 数据源 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<!-- MySQL 数据库 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- phoenix 数据库 -->
<dependency>
    <groupId>org.apache.phoenix</groupId>
    <artifactId>phoenix-core</artifactId>
</dependency>
<!-- mybatis-plus -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>        
</dependency>

接下来,我们需要在application.properties或application.yml文件中配置各个数据源的连接信息。以下是示例配置:

yaml 复制代码
 #数据库配置
  datasource:
    #mysql数据源配置
    mysql:
      type: com.zaxxer.hikari.HikariDataSource
      jdbc-url: jdbc:p6spy:mysql://xxxx:3306/xxxx?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
      username: xxxx
      password: xxxxx
      # Hikari 连接池配置
      # 最小空闲连接数量
      hikari:
        minimum-idle: 5
        # 空闲连接存活最大时间,默认600000(10分钟)
        idle-timeout: 180000
        # 连接池最大连接数,默认是10
        maximum-pool-size: 10
        # 此属性控制从池返回的连接的默认自动提交行为,默认值:true
        auto-commit: true
        # 连接池名称
        pool-name: xxxx-HikariCP
        # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认1800000即30分钟
        max-lifetime: 1800000
        # 数据库连接超时时间,默认30秒,即30000
        connection-timeout: 30000
        connection-test-query: SELECT 1

    #phoenix数据源配置
    phoenix:
      driver: org.apache.phoenix.jdbc.PhoenixDriver
      jdbcUrl: jdbc:phoenix:xxxxx:xxxx
      user:
      password:
      connectionProperties:
      isNamespaceMappingEnabled: true
      mapSystemTablesToNamespace: true
      schema: 'xxxxxx'
      maximumPoolSize: 128
      maxLifetime: 1200000

之后,我们需要创建多个数据源的配置类,以及一些基础的配置。以下是示例代码:

java 复制代码
@EnableTransactionManagement
@Configuration
@MapperScan("com.xxxx.mapper")
public class DataSourceConfig {

    @Autowired
    private PhoenixProperties phoenixProperties;

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor().setDialectType("mysql");
    }


    @Bean(name = "mysqlDateSource")
    @ConfigurationProperties(prefix = "spring.datasource.mysql")
    public HikariDataSource mysqlDateSource() {
        return DataSourceBuilder.create().type(HikariDataSource.class).build();
    }

    @Bean(name = "phoenixDataSource")
    public HikariDataSource phoenixDataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setDriverClassName(phoenixProperties.getDriver());
        dataSource.setJdbcUrl(phoenixProperties.getJdbcUrl());
        dataSource.setUsername(phoenixProperties.getUser());
        dataSource.setPassword(phoenixProperties.getPassword());
        Properties properties = new Properties();
        properties.setProperty("phoenix.schema.isNamespaceMappingEnabled", phoenixProperties.getIsNamespaceMappingEnabled());
        properties.setProperty("phoenix.schema.mapSystemTablesToNamespace", phoenixProperties.getMapSystemTablesToNamespace());
        properties.setProperty("schema", phoenixProperties.getSchema());
        properties.setProperty("maximum-pool-size", phoenixProperties.getMaximumPoolSize());
        properties.setProperty("max-lifetime", phoenixProperties.getMaxLifetime());
        dataSource.setDataSourceProperties(properties);
        return dataSource;
    }

    /**
     * 动态数据源配置
     *
     * @return DataSource
     */
    @Bean
    @Primary
    public DataSource multipleDataSource(@Qualifier("mysqlDateSource") DataSource mysqlDateSource, @Qualifier("phoenixDataSource") DataSource phoenixDataSource) {
        MultipleDataSource multipleDataSource = new MultipleDataSource();
        Map<Object, Object> targetDataSources = Maps.newHashMap();
        targetDataSources.put(DataSourceEnum.MYSQL.getValue(), mysqlDateSource);
        targetDataSources.put(DataSourceEnum.PHOENIX.getValue(), phoenixDataSource);
        //添加数据源
        multipleDataSource.setTargetDataSources(targetDataSources);
        //设置默认数据源
        multipleDataSource.setDefaultTargetDataSource(mysqlDateSource);
        return multipleDataSource;
    }

    @Bean(name = "sqlSessionFactory")
    public SqlSessionFactory sqlSessionFactory() throws Exception {
        MybatisSqlSessionFactoryBean sqlSessionFactory = new MybatisSqlSessionFactoryBean();
        sqlSessionFactory.setDataSource(multipleDataSource(mysqlDateSource(), phoenixDataSource()));
        ResourceLoader loader = new DefaultResourceLoader();
        String resource = "classpath:mybatis-config.xml";
        sqlSessionFactory.setConfigLocation(loader.getResource(resource));
        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        sqlSessionFactory.setMapperLocations(resolver.getResources("classpath*:/mapper/*.xml"));
        sqlSessionFactory.setTypeAliasesPackage("com.huitongjy.oms.web.entity");
        sqlSessionFactory.setTypeEnumsPackage("com.huitongjy.oms.common.enums");
        //关键代码 设置 MyBatis-Plus 分页插件
        Interceptor[] plugins = {paginationInterceptor()};
        sqlSessionFactory.setPlugins(plugins);
        return sqlSessionFactory.getObject();
    }

}

MultipleDataSource类

java 复制代码
public class MultipleDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}

class DataSourceContextHolder {

    private static final ThreadLocal<String> CONTEXT_HOLDER = new InheritableThreadLocal<>();

    /**
     * 设置数据源
     *
     * @param db String
     */
    static void setDataSource(String db) {
        CONTEXT_HOLDER.set(db);
    }

    /**
     * 取得当前数据源
     *
     * @return String
     */
    static String getDataSource() {
        return CONTEXT_HOLDER.get();
    }

    /**
     * 清除上下文数据
     */
    static void clear() {
        CONTEXT_HOLDER.remove();
    }
}

mybatis-config.xml的配置如下:

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <settings>
    <setting name="cacheEnabled" value="false"/>
    <setting name="lazyLoadingEnabled" value="true"/>
    <setting name="multipleResultSetsEnabled" value="true"/>
    <setting name="useColumnLabel" value="true"/>
    <setting name="useGeneratedKeys" value="false"/>
    <setting name="autoMappingBehavior" value="PARTIAL"/>
    <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
    <setting name="defaultExecutorType" value="SIMPLE"/>
    <setting name="defaultStatementTimeout" value="25"/>
    <setting name="defaultFetchSize" value="100"/>
    <setting name="safeRowBoundsEnabled" value="false"/>
    <setting name="mapUnderscoreToCamelCase" value="true"/>
    <setting name="localCacheScope" value="SESSION"/>
    <setting name="jdbcTypeForNull" value="OTHER"/>
    <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
  </settings>
</configuration>

在上面的代码中,我们使用 @ConfigurationProperties(prefix = "spring.datasource.mysql") 将配置文件中的属性绑定到 mysql 的 HikariDataSource 对象上。同样地,我们也为 phoenixDataSource 进行绑定。

这两个数据源分别连接不同的数据库。@Primary注解表示主要的数据源,用于在运行时决定使用哪个数据源。我们创建了一个名为multipleDataSource的方法,该方法添加数据源,并且设置好默认的数据源,

最后,在SqlSessionFactory加载多数据源,以及一些配置文件,这样就可以管理和配置数据库连接。

2.2 项目代码

配置完之后,我们只需要在phoenix接口上配置一下数据源即可,代码如下:

java 复制代码
public interface TestDetailMapper {

    /**
     * 保存
     * @param testDetail
     */
    @DataSource(DataSourceEnum.PHOENIX)
    @Insert(" upsert into xxx_xxx (xxxxx) " +
        " values (#{xxxx})")
    void insert(@Param("xxx") TestDetail testDetail);


    /**
     * 获取内容
     *
     * @param xxxx
     * @return xxx
     */
    @Results(value = {
        @Result(property = "xxxx", column = "xxxxx")
    })
    @DataSource(DataSourceEnum.PHOENIX)
    @Select("SELECT XXXX FROM XXX WHERE XXX=#{XXXX}")
    TestDetail findByKey(@Param("XXXX") String XXXX);

}

通过上述代码,我们已经成功实现了多数据源的整合。

2.3 注意事项

(1)必须指定主数据源,就是在主数据源的bean注入上加一个@Primary注解,表示同一个类的多个对象注入,优先选择有注解@Primary的对象。

(2)不同数据源的dao和mapper文件最好分开到不同包路径和文件路径下,这样才能单独的配置文件映射,不然会出错。

相关推荐
monkey_meng几秒前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
天天进步20152 分钟前
Vue+Springboot用Websocket实现协同编辑
vue.js·spring boot·websocket
草莓base13 分钟前
【手写一个spring】spring源码的简单实现--bean对象的创建
java·spring·rpc
Estar.Lee15 分钟前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
drebander37 分钟前
使用 Java Stream 优雅实现List 转化为Map<key,Map<key,value>>
java·python·list
乌啼霜满天24941 分钟前
Spring 与 Spring MVC 与 Spring Boot三者之间的区别与联系
java·spring boot·spring·mvc
tangliang_cn1 小时前
java入门 自定义springboot starter
java·开发语言·spring boot
程序猿阿伟1 小时前
《智能指针频繁创建销毁:程序性能的“隐形杀手”》
java·开发语言·前端
Grey_fantasy1 小时前
高级编程之结构化代码
java·spring boot·spring cloud
新知图书1 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust