mybatis-plus整合dynamic-datasource-spring-boot-starter之手动切换多数据源支持多种不同数据库类型(“坎坷之路”)

简介:今天公司有一个这样场景业务,简单来说需要动态第三方数据源数据库,数据源信息,一开始根据想要查看的表进行一个表的信息与表的数据库信息获取,然后保存本地库内,用户可在界面点击获取到的表进行业务数据处理,需求重点:数据库是动态(会有不同类型数据库,也可能会有多种同种类型数据库),表字段是动态(不同数据库不同字段),所以根据这几点来处理你的CRUD,经过几天资源分析官网搜索,终于找到简洁并且效率性的多数据源实现方式,菜鸡一枚,唔介意。


在这里插入图片描述

1、废话不多说,首先引入依赖(备注:注意这里的依赖,版本不同会出现让人头炸的BUG,所以配置依赖是关键,网上搜索都是半句话压根没结果性,所以要注意)

 <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.4</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.2.4</version>
    </dependency>

2、配置主数据源(这里只需配置主数据源)

spring:
  datasource:
    dynamic:
      primary: master #这里是本地主库,主要用来存储第三方数据源配置信息表及用户表的选择
      strict: false
      datasource:
        master:
          url: jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&serverTimezone=GMT%2B8
          username: root
          password: 123456
          driverClassName: com.mysql.cj.jdbc.Driver
          type: com.alibaba.druid.pool.DruidDataSource
          druid:
            maxActive: 300
            initialSize: 20
            maxWait: 6000
            minIdle: 20
            timeBetweenEvictionRunsMillis: 60000
            minEvictableIdleTimeMillis: 30000
            validationQuery: select 'x'
            testWhileIdle: true
            testOnBorrow: true
            testOnReturn: false

3、配置公共数据源切换类(备注我这里的子库链接信息是存储在主库表内,流程-》主库内获取数据配置信息表-》写入到DataSourceProperty的对象内,然后加入到核心数据源组件内)

package com.kk.datamap.masterdata.common.dbconfig;


import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.*;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.kk.datamap.masterdata.common.constant.SystemConstants;
import com.kk.datamap.masterdata.po.CdcDatasourceConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;


import javax.sql.DataSource;
import java.util.Set;


/**
 * @author: kk
 * @Email: 2919529566@qq.com
 * @Description: 公共动态数据源配置类
 * @date: 2022/1/14 5:25 下午
 * @Version V1.0
 */
@Service
public class DynamicDataSourceConfig {
    @Autowired
    DataSource dataSource;
    @Autowired
    DefaultDataSourceCreator dataSourceCreator;

    /**
     * 获取当前数据源
     *
     * @return
     */
    public Set<String> dataSourceNow() {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        return ds.getDataSources().keySet();
    }


    /**
     * 添加数据源
     *
     * @param dto
     * @return
     */
    public Set<String> add(DatasourceConfig dto) {
        DataSourceProperty dataSourceProperty = new DataSourceProperty();
        dataSourceProperty.setDriverClassName(dto.getDriverClassName());
        dataSourceProperty.setUrl(dto.getDatabaseIp());
        dataSourceProperty.setUsername(dto.getDatabaseAccount());
        dataSourceProperty.setPassword(dto.getDatabasePassword());
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
        ds.addDataSource(dto.getDatasourceType(), dataSource);//这里写入ds注解的时候建议制定同种类型数据库走一个ds注解值(我这里实际需求会从数据库获取自定义的ds注解值)
        return ds.getDataSources().keySet();
    }


    /**
     * 删除数据源
     *
     * @param name
     * @return
     */
    public String remove(String name) {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        ds.removeDataSource(name);
        return name + "删除成功!";
    }

}

5、定义实体类对象

package com.kk.datamap.masterdata.po;


import com.alibaba.druid.support.monitor.annotation.MTable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;


/**
 * datasource_config
 * @author 
 */
@ApiModel(value="数据源配置表")
@Data
public class DataSourceConfig implements Serializable {
    private Integer id;


    /**
     * 数据源ID
     */
    @ApiModelProperty(value="数据源ID")
    private Integer datasourceId;


    /**
     * 主数据ID
     */
    @ApiModelProperty(value="主数据ID")
    private Integer mdmModelId;


    /**
     * 数据源类型
     */
    @ApiModelProperty(value="数据源类型")
    private String datasourceType;


    /**
     * 数据库IP
     */
    @ApiModelProperty(value="数据库IP")
    private String databaseIp;


    /**
     * 数据库端口
     */
    @ApiModelProperty(value="数据库端口")
    private String databasePort;


    /**
     * 数据库名
     */
    @ApiModelProperty(value="数据库名")
    private String databaseName;


    /**
     * 数据库账户名
     */
    @ApiModelProperty(value="数据库账户名")
    private String databaseAccount;


    /**
     * 数据库密码
     */
    @ApiModelProperty(value="数据库密码")
    private String databasePassword;


    /**
     * 创建人
     */
    @ApiModelProperty(value="创建人")
    private String creator;


    /**
     * 创建时间
     */
    @ApiModelProperty(value="创建时间")
    private Date createTime;


    /**
     * 修改人
     */
    @ApiModelProperty(value="修改人")
    private String updator;


    /**
     * 修改时间
     */
    @ApiModelProperty(value="修改时间")
    private Date updateTime;

    /**
     * 数据源驱动名
     */
    @ApiModelProperty("数据源驱动名")
    private String driverClassName;

    private static final long serialVersionUID = 1L;
}

6、定义子库mapper(备注:这里主库可以随意创建mapper,子库只需增加@DS(”“)注解)

package com.kk.datamap.masterdata.dao.datatype;


import com.baomidou.dynamic.datasource.annotation.DS;
import com.kk.datamap.masterdata.common.constant.SystemConstants;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;


import java.util.List;
import java.util.Map;


/**
 * @author: kk
 * @Email: 2919529566@qq.com
 * @Description:
 * @date: 2022/1/13 4:53 下午
 * @Version V1.0
 */
@Mapper
public interface MySqlMapper {

    //备注:这里我定义的是一个公共DS组件,但是我们实际需求是支持多种不同数据库(并且可能会有两个或者多个同种类型数据库)所以这种情况下建议相同数据库类型可以制定同一个注解(例如:MySQL可以制定@DS(“mysql”),PG可以制定为@DS(”pg”)等)其次注意建议要放置在不同mapper或者不同方法上
    @DS(“mysql”)
    List<Map<String, Object>> selectByMySqlDataSourceId(@Param("fields") String fields, @Param("tableName") String tableName);

    @DS(“pg")
    List<Map<String, Object>> selectByPgDataSourceId(@Param("fields") String fields, @Param("tableName") String tableName);
    
    @DS(“oracle")
    List<Map<String, Object>> selectByOracleDataSourceId(@Param("fields") String fields, @Param("tableName") String tableName);
}

6、定义xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.gennlife.datamap.masterdata.dao.datatype.CDCMySqlMapper">

    <select id="selectByDataSourceId" resultType="java.util.LinkedHashMap">
        SELECT ${fields}
        FROM ${tableName}
    </select>
</mapper>

7、单元测试

@Autowired
DynamicDataSourceConfig dynamicDataSourceConfig;
@Autowired
MySqlMapper mySqlMapper;
@Autowired
DatasourceConfigMapper datasourceConfigMapper;


@Test
public void Test(){
    //数据库切换(注:我这里只会增加子数据源,主数据源不会影响,删除的时候也是删除子数据源)
    DatasourceConfig datasourceConfig = datasourceConfigMapper.selectByModelId(requestBody.getModelId());
    Set<String> addDataSource = dynamicDataSourceConfig.add(datasourceConfig);
    log.info("当前已增加数据源为:" + JSON.toJSON(addDataSource));
    List<Map<String, Object>> list = mySqlMapper.selectByDataSourceId(StringUtils.strip(fieldList.toString(), "[]"), modelInfo.getModelName());
    String dataSourceName = dynamicDataSourceConfig.remove(datasourceConfig.getDatasourceType());
    log.info("当前已删除数据源为:" + dataSourceName);
    //拼接数据库类型mapper
    System.out.println(JSON.toJSON(list));
}

总结结果(这里只是大致使用流程,如果后期接触数据场景,建议深入研究下dynamicDataSource底层源码,其次DS注解也可以动态后面可以优化下,有新的想法欢迎一起留言沟通):

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
mybatis-plus-dynamic-datasource 获取多数据源实例的方法如下: 1. 导入相关依赖: ```xml <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>2.5.3</version> </dependency> ``` 2. 在 application.yml 或 application.properties 配置数据源信息,例如: ```yaml spring: datasource: dynamic: primary: ds1 # 设置默认数据源 datasource: ds1: url: jdbc:mysql://localhost:3306/db1 username: root password: 123456 ds2: url: jdbc:mysql://localhost:3306/db2 username: root password: 123456 ``` 3. 创建一个继承自 AbstractRoutingDataSource 的类,用于动态切换数据源: ```java public class DynamicRoutingDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceContextHolder.getDataSourceKey(); } } ``` 4. 创建一个数据源上下文持有者类,用于设置和获取当前线程使用的数据源: ```java public class DynamicDataSourceContextHolder { private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); public static void setDataSourceKey(String dataSourceKey) { CONTEXT_HOLDER.set(dataSourceKey); } public static String getDataSourceKey() { return CONTEXT_HOLDER.get(); } public static void clearDataSourceKey() { CONTEXT_HOLDER.remove(); } } ``` 5. 配置数据源切换策略和数据源 bean: ```java @Configuration public class DataSourceConfig { @Bean @ConfigurationProperties(prefix = "spring.datasource.dynamic") public DataSourceProperties dataSourceProperties() { return new DataSourceProperties(); } @Bean public DataSource dataSource(DataSourceProperties properties) { Map<String, DataSource> dataSourceMap = new HashMap<>(); dataSourceMap.put("ds1", properties.getDataSource("ds1")); dataSourceMap.put("ds2", properties.getDataSource("ds2")); // 设置默认数据源 DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource(); dataSource.setDefaultTargetDataSource(dataSourceMap.get(properties.getPrimary())); dataSource.setTargetDataSources(dataSourceMap); return dataSource; } @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean(); sessionFactoryBean.setDataSource(dataSource); return sessionFactoryBean.getObject(); } @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } } ``` 现在,你可以通过注入 DataSource 类型的 bean 来获取多数据源实例,例如: ```java @Autowired private DataSource dataSource; ``` 然后,你就可以使用这个数据源实例来执行数据库操作了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值