SpringBoot多数据源(1):多数据源基础配置

SpringBoot多数据源配置


1、多套数据源配置

https://github.com/zhengguofeng1998/DynamicDataSource/tree/master/FirstDemo

1.1、项目目录

项目结构

1.2、配置文件

server:
  port: 1815
spring:
  datasource:
    primary:
      url: jdbc:mysql://localhost:3306/seata_account?useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: root
      password: 123456
      driver-class-name: org.gjt.mm.mysql.Driver
    slave:
      url: jdbc:mysql://localhost:3306/seata_order?useUnicode=true&characterEncoding=utf-8&useSSL=false
      username: root
      password: 123456
      driver-class-name: org.gjt.mm.mysql.Driver
  application:
    name: basic-multi-datasource

1.3、多数据源配置

1.3.1、主数据源配置

@Configuration
@MapperScan(basePackages = "com.zgf.springcloud.mapper.primary", sqlSessionFactoryRef = "primaryDataSource")
public class PrimaryDataSourceConfig {

    @Bean("primary")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DruidDataSource druidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setInitialSize(0);
        druidDataSource.setMaxActive(180);
        druidDataSource.setMaxWait(60000);
        druidDataSource.setMinIdle(0);
        druidDataSource.setValidationQuery("Select 1 from DUAL");
        druidDataSource.setTestOnBorrow(false);
        druidDataSource.setTestOnReturn(false);
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
        druidDataSource.setMinEvictableIdleTimeMillis(25200000);
        druidDataSource.setRemoveAbandoned(true);
        druidDataSource.setRemoveAbandonedTimeout(1800);
        druidDataSource.setLogAbandoned(true);
        return druidDataSource;
    }


    @Bean
    public SqlSessionFactory primaryDataSource(@Qualifier("primary") DruidDataSource druidDataSource) throws Exception {
        // 设置数据源
        MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        mybatisSqlSessionFactoryBean.setDataSource(druidDataSource);
        //mapper的xml文件位置
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        String locationPattern = "classpath*:/mapper/primary/*.xml";
        mybatisSqlSessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern));
        //对应数据库的entity位置
        String typeAliasesPackage = "com.zgf.springcloud.domain.primary";
        mybatisSqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);
        return mybatisSqlSessionFactoryBean.getObject();
    }
}

1.3.2、从数据源配置

@Configuration
@MapperScan(basePackages = "com.zgf.springcloud.mapper.slave", sqlSessionFactoryRef = "slaveDataSource")
public class SlaveDataSourceConfig {

    @Bean(value = "slave")
    @ConfigurationProperties(prefix = "spring.datasource.slave")
    public DruidDataSource druidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setInitialSize(0);
        druidDataSource.setMaxActive(180);
        druidDataSource.setMaxWait(60000);
        druidDataSource.setMinIdle(0);
        druidDataSource.setValidationQuery("Select 1 from DUAL");
        druidDataSource.setTestOnBorrow(false);
        druidDataSource.setTestOnReturn(false);
        druidDataSource.setTestWhileIdle(true);
        druidDataSource.setTimeBetweenEvictionRunsMillis(60000);
        druidDataSource.setMinEvictableIdleTimeMillis(25200000);
        druidDataSource.setRemoveAbandoned(true);
        druidDataSource.setRemoveAbandonedTimeout(1800);
        druidDataSource.setLogAbandoned(true);
        return druidDataSource;
    }


    @Bean
    public SqlSessionFactory slaveDataSource(@Qualifier("slave") DruidDataSource druidDataSource) throws Exception {
        // 设置数据源
        MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
        mybatisSqlSessionFactoryBean.setDataSource(druidDataSource);
        //mapper的xml文件位置
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        String locationPattern = "classpath*:/mapper/slave/*.xml";
        mybatisSqlSessionFactoryBean.setMapperLocations(resolver.getResources(locationPattern));
        //对应数据库的entity位置
        String typeAliasesPackage = "com.zgf.springcloud.domain.slave";
        mybatisSqlSessionFactoryBean.setTypeAliasesPackage(typeAliasesPackage);
        return mybatisSqlSessionFactoryBean.getObject();
    }
}

  • 注解 @MapperScan 指定那些包下的 mapper 使用本数据源,并指定使用哪个SqlSessionFactory,注意,此处的 sqlSessionFactoryRef 即本配置中的注入的 SqlSessionFactory
  • 设置指定的数据源,此处是名为 primary的数据源,使用 @Qualifier 指定。
  • MyBatis Plus 对应的 Mapper 若有自定义的 mapper.xml, 则使用 setMapperLocations 指定。
  • 若需要对实体进行别名处理,则使用 setTypeAliasesPackage 指定。

然后就是正常的controller…dao等,没有区别,唯一需要注意的是mapper.xml的位置要和@MapperScan指定的路径进行对应。

2、优缺点

2.1、优点

  • 简单、直接:一个库对应一套处理方式,很好理解。

  • 符合开闭原则( OCP ):开发的设计模式告诉我们,对扩展开放,对修改关闭,添加多一个数据库,原来的那一套不需要改动,只添加即可。

2.2、缺点

  • 资源浪费:针对每一个数据源写一套操作,连接数据库的资源也是独立的,分别占用同样多的资源。SqlSessionFactory 是一个工厂,建议是使用单例,完全可以重用,不需要建立多个,只需要更改数据源即可,跟多线程,使用线程池减少资源消耗是同一道理。
  • 代码冗余:在前面的多数据源配置中可以看出,其实 primaryslave 的很多操作是一样的,只是改个名称而已,因此会造成代码冗余。
  • 缺乏灵活:所有需要使用的地方都需要引入对应的 mapper,对于很多操作,只是选择数据源的不一样,代码逻辑是一致的。另外,对于一主多从的情况,若需要对多个从库进行负载均衡,相对比较麻烦。

改进见后续文章。

3、另一种方法

通过引入jar包的形式进行配置即可,进行了封装,通过@DS注解的value指定来使用对应的数据源。

如下所示,指定对应的order-ds
@DS(value = "order-ds")

<!-- https://mvnrepository.com/artifact/com.baomidou/dynamic-datasource-spring-boot-starter -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>3.5.1</version>
</dependency>

spring:
  application:
    name: multi-datasource-service  # 应用名
  datasource:
    # dynamic-datasource-spring-boot-starter 动态数据源的配配项,对应 DynamicDataSourceProperties 类
    dynamic:
      primary: order-ds # 设置默认的数据源或者数据源组,默认值即为 master
      datasource:
        # 订单 order 数据源配置
        order-ds:
          url: jdbc:mysql://127.0.0.1:3306/seata_order?useSSL=false&useUnicode=true&characterEncoding=UTF-8
          driver-class-name: com.mysql.jdbc.Driver
          username: root
          password:
        # 账户 pay 数据源配置
        amount-ds:
          url: jdbc:mysql://127.0.0.1:3306/seata_pay?useSSL=false&useUnicode=true&characterEncoding=UTF-8
          driver-class-name: com.mysql.jdbc.Driver
          username: root
          password:
        # 库存 storage 数据源配置
        storage-ds:
          url: jdbc:mysql://127.0.0.1:3306/seata_storage?useSSL=false&useUnicode=true&characterEncoding=UTF-8
          driver-class-name: com.mysql.jdbc.Driver
          username: root
          password:

3.1、特性

  • 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
  • 支持数据库敏感配置信息 加密(可自定义) ENC()。
  • 支持每个数据库独立初始化表结构schema和数据库database。
  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
  • 支持 自定义注解 ,需继承DS(3.2.0+)。
  • 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。
  • 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。
  • 提供 自定义数据源来源 方案(如全从数据库加载)。
  • 提供项目启动后 动态增加移除数据源 方案。
  • 提供Mybatis环境下的 纯读写分离 方案。
  • 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
  • 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
  • 提供 基于seata的分布式事务方案
  • 提供 本地多数据源事务方案。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值