mybatis-plus动态数据源读写分离方式

 更新时间:2024年10月23日 09:00:58   作者:杨村你喜哥l  
在分布式项目开发中,动态数据源的配置与使用至关重要,通过创建DynamicDatasourceService,实现数据源的动态添加与调用,有效管理主从库操作,减轻数据库压力,此外,通过配置类与@DS注解,实现了灵活的分库查询功能,为高效处理数据提供了强有力的支持

1、背景

在实际项目的开发过程中,一定会存在主库与从库的分布式模式,主库进行增删改,从库进行查询。

这样可以保证对不同的数据库进行操作,减少对数据库的压力。

2、动态数据源

创建DynamicDatasourceService

import com.jiuqi.grid.collection.entity.datasource.DataSourceDTO;
import java.util.Set;
public interface DynamicDatasourceService {


    /**
     * 获取所有数据源
     *
     * @return
     */
    Set<String> datasources();


    /**
     * 添加数据源
     *
     * @param dto 数据源信息
     * @return
     */
    Set<String> add(DataSourceDTO dto);


    /**
     * 移除数据源
     *
     * @param name 连接池名称
     */
    void remove(String name);
}

实现DynamicDatasourceService

package com.jiuqi.grid.collection.service.impl;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.jiuqi.grid.collection.entity.datasource.DataSourceDTO;
import com.jiuqi.grid.collection.service.DynamicDatasourceService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

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

@Service
public class DynamicDatasourceServiceImpl implements DynamicDatasourceService {


    private final DataSource dataSource;

    private final DefaultDataSourceCreator dataSourceCreator;

    public DynamicDatasourceServiceImpl(
            DataSource dataSource, DefaultDataSourceCreator dataSourceCreator) {
        this.dataSource = dataSource;
        this.dataSourceCreator = dataSourceCreator;
    }


    /**
     * 获取所有数据源
     *
     * @return
     */
    @Override
    public Set<String> datasources() {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        return ds.getDataSources().keySet();
    }


    /**
     * 添加数据源
     *
     * @param dto
     * @return
     */
    @Override
    public Set<String> add(DataSourceDTO dto) {
        DataSourceProperty dataSourceProperty = new DataSourceProperty();
        BeanUtils.copyProperties(dto, dataSourceProperty);
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
        ds.addDataSource(dto.getPollName(), dataSource);
        return ds.getDataSources().keySet();
    }


    /**
     * 删除数据源
     *
     * @param name
     */
    @Override
    public void remove(String name) {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        ds.removeDataSource(name);
    }

}

2.1添加数据源

我这里是读取的配置文件里的用户名、密码等数据源的链接

 public void addDatasource(String tenant) {
        if (dynamicDatasourceService.datasources().contains(tenant)) {
            return;
        }
        DataSourceDTO datasourceDTO = new DataSourceDTO();
        //库名
        datasourceDTO.setPollName(tenant);
        //链接信息 读取配置文件的主库信息
        datasourceDTO.setDriverClassName(sqlDataSource.getDriverClassName());
        //替换数据库
        if (StringUtils.isEmpty(sqlDataSource.getUrl())) {
            throw new RuntimeException("配置文件读取失败");
        }
        String url = sqlDataSource.getUrl();
        url = url.replace("grid_test", tenant);
        datasourceDTO.setUrl(url);
        datasourceDTO.setUsername(sqlDataSource.getUsername());
        datasourceDTO.setPassword(sqlDataSource.getPassword());
        dynamicDatasourceService.add(datasourceDTO);
    }

2.2数据源

调用上面的addDatasource()方法,数据源就会创建成功,这里要注意的是,每一次增删改查都需要调用此方法,以防数据源不存在。

3、分库查询

创建新的数据源目的就是为了可以进行分库操作。

分库操作步骤如下:

3.1添加配置类

package com.jiuqi.grid.collection.dsprocessor;

import com.baomidou.dynamic.datasource.processor.DsHeaderProcessor;
import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.processor.DsSessionProcessor;
import com.baomidou.dynamic.datasource.processor.DsSpelExpressionProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 注册动态数据源解析器
 */
@Configuration
public class MyDynamicDataSourceConfig {

  @Bean
  public DsProcessor dsProcessor() {
    DsMapProcessor mapProcessor = new DsMapProcessor();
    DsHeaderProcessor headerProcessor = new DsHeaderProcessor();
    DsSessionProcessor sessionProcessor = new DsSessionProcessor();
    DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor();
    mapProcessor.setNextProcessor(headerProcessor);
    headerProcessor.setNextProcessor(sessionProcessor);
    sessionProcessor.setNextProcessor(spelExpressionProcessor);
    return mapProcessor;
  }
}
package com.jiuqi.grid.collection.dsprocessor;

import com.baomidou.dynamic.datasource.processor.DsProcessor;
import java.util.Map;
import com.jiuqi.grid.collection.consts.SQLConstants;
import com.jiuqi.grid.collection.dto.common.Address3DTO;
import com.jiuqi.grid.collection.dto.data.CollectionDataPageParam;
import com.jiuqi.grid.collection.entity.CollectionDataDO;
import org.aopalliance.intercept.MethodInvocation;

/**
 * 通过params map中获取数据源标识
 *
 * @author songlude
 */
public class DsMapProcessor extends DsProcessor {

    /**
     * 抽象匹配条件 匹配才会走当前执行器否则走下一级执行器
     *
     * @param key DS注解里的内容
     * @return 是否匹配
     */
    @Override
    public boolean matches(String key) {
        return key.equals("#" + SQLConstants.EXEC_DATASOURCE);
    }

    /**
     * 抽象最终决定数据源
     *
     * @param invocation 方法执行信息
     * @param key        DS注解里的内容
     * @return 数据源名称
     */
    @Override
    public String doDetermineDatasource(MethodInvocation invocation, String key) {
        Object[] arguments = invocation.getArguments();
        Object argument = arguments[0];

        if (argument instanceof Map) {
            Map<String, Object> params = (Map<String, Object>) argument;
            Object value = params.get(SQLConstants.EXEC_DATASOURCE);
            return value == null ? null : value.toString();
        } else if (argument instanceof CollectionDataPageParam) {
            CollectionDataPageParam collectionDataPageParam = (CollectionDataPageParam) argument;
            return collectionDataPageParam.getGRID_DATASOURCE();
        } else if (argument instanceof CollectionDataDO) {
            CollectionDataDO collectionDataDO = (CollectionDataDO) argument;
            return collectionDataDO.getGRID_DATASOURCE();
        } else if (argument instanceof Address3DTO) {
            Address3DTO address3DTO = (Address3DTO) argument;
            return address3DTO.getGRID_DATASOURCE();
        }
        return null;
    }
}

这里要注意需要把“argument”进行类型的判断,argument 就是你查询Mapper的参数,这里我获取的是argument[0],则Mapper参数的位置在第一个。

3.2 添加数据源查询

通过@DS注解来指定数据源,在配置类中指定了以#开头

 @DS("#GRID_DATASOURCE")
    @UpdateProvider(type = QueryProvider.class, method = "createDatabase")
    void createDatabase(Map<String, Object> params);

这样就可以开启你的动态数据源,分库查询啦。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Java源码解析之Gateway请求转发

    Java源码解析之Gateway请求转发

    今天给大家带来的是关于Java的相关知识,文章围绕着Gateway请求转发展开,文中有非常详细介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • Java基础之重载(Overload)与重写(Override)详解

    Java基础之重载(Overload)与重写(Override)详解

    这篇文章主要介绍了Java基础之重载(Overload)与重写(Override)详解,文中有非常详细的代码示例,对正在学习java基础的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-04-04
  • Java中操作Redis的详细方法

    Java中操作Redis的详细方法

    基于Jedis实现对redis中字符串的操作,文中通过实例代码给大家介绍的非常详细,包括连接池JedisPool应用的实例代码,对Java操作Redis的相关知识感兴趣的朋友一起看看吧
    2021-11-11
  • 全面解析Hibernate关联操作、查询操作、高级特性、并发处理机制

    全面解析Hibernate关联操作、查询操作、高级特性、并发处理机制

    这篇文章主要介绍了全面解析Hibernate关联操作、查询操作、高级特性、并发处理机制的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • JAVA实现LRU算法的参考示例

    JAVA实现LRU算法的参考示例

    这篇文章主要介绍了JAVA实现LRU算法的参考示例,帮助大家根据需求实现算法,感兴趣的朋友可以了解下
    2020-10-10
  • 简单易懂的MyBatis分库分表方案分享

    简单易懂的MyBatis分库分表方案分享

    这篇文章主要给大家介绍了关于MyBatis分库分表方案的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者使用MyBatis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-03-03
  • Java13 明天发布(最新最全新特性解读)

    Java13 明天发布(最新最全新特性解读)

    这篇文章主要介绍了Java13 明天发布,最新最全新特性解读,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • SpringCloud Gateway动态转发后端服务实现过程讲解

    SpringCloud Gateway动态转发后端服务实现过程讲解

    这篇文章主要介绍了SpringCloud Gateway动态转发后端服务实现过程,简单的路由转发可以通过SpringCloudGateway的配置文件实现,在一些业务场景种,会需要动态替换路由配置中的后端服务地址,单纯靠配置文件无法满足这种需求
    2023-03-03
  • Spring Boot webflux使用方法解析

    Spring Boot webflux使用方法解析

    这篇文章主要介绍了Spring Boot webflux使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • Nebula Graph介绍和SpringBoot环境连接和查询操作

    Nebula Graph介绍和SpringBoot环境连接和查询操作

    Nebula Graph 是一款开源的、分布式的、易扩展的原生图数据库,能够承载包含数千亿个点和数万亿条边的超大规模数据集,并且提供毫秒级查询,这篇文章主要介绍了Nebula Graph介绍和SpringBoot环境连接和查询,需要的朋友可以参考下
    2022-10-10

最新评论