SpringBoot+dynamic-datasource实现多数据源(msyql、sqlserver、postgresql)手动切换

本文主要是介绍SpringBoot+dynamic-datasource实现多数据源(msyql、sqlserver、postgresql)手动切换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

场景

SpringBoot+MybatisPlus+dynamic-datasources实现连接Postgresql和mysql多数据源:

SpringBoot+MybatisPlus+dynamic-datasources实现连接Postgresql和mysql多数据源-CSDN博客

上面实现通过注解和配置文件的方式去进行多数据源操作。

如果业务需求,比如查询第三方接口时提供的是sqlserver的视图连接方式时,需要在调用

接口时手动新增数据源-检验数据源是否可用-切换当前数据源-查询数据-清除当前数据源

实现以上流程,可以通过mybatisplus的dynamic-datasource来实现。

dynamic-datasource

开源文档付费

基础必读(免费) · dynamic-datasource · 看云

多数据源 | MyBatis-Plus

但是可以通过引入依赖后查看其源码以及借助网上一些教程,可以找到源码中需要用到的几个类

注:

博客:
霸道流氓气质-CSDN博客

实现

1、引入pom依赖

这里springboot的版本是2.6.13

dynamic-datasource的版本是3.2.1

        <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.2.1</version></dependency>

引入msyql、sqlserver、postgresql所需的依赖

        <!--MySQL驱动--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId></dependency><!-- sqlserver--><dependency><groupId>com.microsoft.sqlserver</groupId><artifactId>mssql-jdbc</artifactId><version>7.4.1.jre8</version></dependency>

引入Mybatisplus所需依赖

        <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency>

引入其他依赖

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>   <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>

2、这里使用默认的HikariCP数据库连接池,没使用Druid,流程一样

参考上面博客已经实现了连接Mysql和sqlserver多数据源

spring:datasource:dynamic:primary: master #设置默认的数据源或者数据源组,默认值即为masterstrict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源datasource:master:url:jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverdbcp2:min-idle: 5                                # 数据库连接池的最小维持连接数initial-size: 5                            # 初始化连接数max-total: 5                               # 最大连接数max-wait-millis: 150                       # 等待连接获取的最大超时时间pg:url: jdbc:postgresql://127.0.0.1:5432/testusername: postgrespassword: 123456driver-class-name: org.postgresql.Driverdbcp2:min-idle: 5                                # 数据库连接池的最小维持连接数initial-size: 5                            # 初始化连接数max-total: 5                               # 最大连接数max-wait-millis: 150                       # 等待连接获取的最大超时时间

3、SpringBoot+dynamic-datasource使用DynamicRoutingDataSource获取当前所有数据源

代码实现:

@SpringBootTest
class DynamicDataSourceTest {@Autowiredprivate DataSource dataSource;/*** 获取当前所有数据源*/@Testvoid getAllDataSource() {DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;System.out.println(ds.getCurrentDataSources().keySet());}
}

其中DataSource是javax.sql包下的。

javax.sql.DataSource 是 jdk 提供的接口,各个连接池厂商 和 Spring 都对 DataSource 进行了设计和实现。

javax.sql.DataSource 是连接到物理数据源的工厂接口。它是 java.sql.DriverManager 功能的替代者,

是获取数据库连接的首选方法。

DataSource 数据源在必要时可以修改它的属性。例如,如果将数据源移动到其他服务器,

则可以更改 DataSource 的属性,这样访问该数据源的代码不需要做任何更改就可以获取到达到目的。

单元测试运行结果:

4、SpringBoot+DynamicRoutingDataSources实现添加与删除数据源

这里通过代码将sqlserver的数据源添加到DynamicRoutingDataSource中

这就需要用到creator包下的各种创建器

这里是默认HikariCP的连接池,所以使用该创建器,如果是其它类型则使用对应的创建器。

数据源创建需要的参数这里新建一个DTO类用来赋值

import lombok.Builder;
import lombok.Data;@Data
@Builder
public class DataSourceDTO {private String dataSourceName;private String driverClassName;private String url;private String username;private String password;
}

编写单元测试

@SpringBootTest
class DynamicDataSourceTest {@Autowiredprivate DataSource dataSource;@Autowired(required = false)private HikariDataSourceCreator hikariDataSourceCreator;/*** 获取当前所有数据源*/@Testvoid getAllDataSource() {DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;System.out.println(ds.getCurrentDataSources().keySet());}/*** 添加 与 删除 HikariCP数据源*/@Testvoid addHcpDataSource() {DataSourceDTO sqlserver = DataSourceDTO.builder().dataSourceName("sqlserver").driverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver").url("jdbc:sqlserver://127.0.0.1:1433;DatabaseName=test").username("sa").password("123456").build();DataSourceProperty dataSourceProperty = new DataSourceProperty();BeanUtils.copyProperties(sqlserver,dataSourceProperty);DataSource sqlserverDataSource = hikariDataSourceCreator.createDataSource(dataSourceProperty);DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;ds.addDataSource(sqlserver.getDataSourceName(),sqlserverDataSource);System.out.println(ds.getCurrentDataSources().keySet());ds.removeDataSource(sqlserver.getDataSourceName());System.out.println(ds.getCurrentDataSources().keySet());}
}

单元测试运行结果:

5、SpringBoot中+HikariCP实现检测数据源是否可用

预实现手动切换当前数据源,首先需要确保配置的数据源的相关参数可以正常连接可用

新建检测数据源的方法

    /***  检测数据源* @param dataSourceDTO* @return*/private boolean checkDataBase(DataSourceDTO dataSourceDTO){Connection connection = null;try {DataSource dataSource = creatHcpDataSource(dataSourceDTO);connection = dataSource.getConnection();Statement statement = connection.createStatement();statement.execute("select * from s_user");return true;} catch (Exception exception) {return false;}finally {try {if(null!=connection){connection.close();}} catch (SQLException throwables) {throwables.printStackTrace();}}}

这其中就是创建数据源并进行连接和执行sql,确保无异常发生则代表连接可用,这里执行的sql以及表名

均写死,其中s_user是sqlserver中新建的表。

用到创建数据源的方法creatHcpDataSource的实现

    /*** 创建Hcp datasource* @param dataSourceDTO* @return*/private DataSource creatHcpDataSource(DataSourceDTO dataSourceDTO){HikariDataSource dataSource = new HikariDataSource();//控制客户端(即用户程序)等待池中连接的最长毫秒数。如果在没有连接可用的情况下超过此时间,则将抛出SQLException异常。最低可以接受的连接超时为250毫秒。默认值:3000(30秒)。这是一个很重要的问题排查指标dataSource.setConnectionTimeout(3000l);//HikariCP将尝试仅基于jdbcUrl通过DriverManager解析驱动程序,但对于某些较旧的驱动程序必须指定driverClassName。除非用户收到明显的错误消息,表明未找到驱动程序,否则可忽略此属性。默认值:无//dataSource.setDataSourceClassName(dataSourceDTO.getDriverClassName());dataSource.setJdbcUrl(dataSourceDTO.getUrl());dataSource.setUsername(dataSourceDTO.getUsername());dataSource.setPassword(dataSourceDTO.getPassword());//表示连接池的用户定义名称,主要显示在日志记录和JMX管理控制台中,以标识池和池配置。该属性的默认值:自动生成dataSource.setPoolName(dataSourceDTO.getDataSourceName());return dataSource;}

相关参数和配置自行搜索和设置,这里重点关注

dataSource.setConnectionTimeout(3000l);

设置超时时间3秒。

控制客户端(即用户程序)等待池中连接的最长毫秒数。如果在没有连接可用的情况下超过此时间,则将抛出SQLException异常。

最低可以接受的连接超时为250毫秒。默认值:3000(30秒)。这是一个很重要的问题排查指标

dataSource.setPoolName

示连接池的用户定义名称,主要显示在日志记录和JMX管理控制台中,以标识池和池配置。该属性的默认值:自动生成

编写单元测试:

    /*** 检测数据源*/@Testvoid testDataSource(){DataSourceDTO sqlserver = DataSourceDTO.builder().dataSourceName("sqlserver").driverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver").url("jdbc:sqlserver://127.0.0.1:1433;DatabaseName=test").username("sa").password("123456").build();boolean checkDataBase = checkDataBase(sqlserver);System.out.println(checkDataBase);DataSourceDTO sqlserverWrong = DataSourceDTO.builder().dataSourceName("sqlserver").driverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver").url("jdbc:sqlserver://192.168.1.2:1433;DatabaseName=test").username("sa").password("123456").build();boolean checkDataBaseWrong = checkDataBase(sqlserverWrong);System.out.println(checkDataBaseWrong);}

第二个故意写了一个不存在的数据源的地址

运行单元测试:

6、SpringBoot+DynamicDataSourceContextHolder实现手动切换清除当前数据源

动态数据源切换的关键在于DynamicDataSourceContextHolder类,它提供了一种机制来存储当前使用的数据源。

它主要由两部分组成,一部分是线程本地的数据源容器,另一部分是管理动态数据源的数据源切换类。

查看其源码

主要用到的方法

push 设置当前线程数据源 如非必要不要手动调用,调用后确保最终清除

poll 清空当前线程数据源 如果当前线程是连续切换数据源 只会移除掉当前线程的数据源名称

clear 强制清空本地线程  防止内存泄漏,如手动调用了push可调用此方法确保清除

编写单元测试:

    /*** 手动切换数据源*/@Testvoid changeDataSource() {DataSourceDTO sqlserver = DataSourceDTO.builder().dataSourceName("sqlserver").driverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver").url("jdbc:sqlserver://127.0.0.1:1433;DatabaseName=test").username("sa").password("123456").build();boolean checkDataBase = checkDataBase(sqlserver);if(checkDataBase){DataSourceProperty dataSourceProperty = new DataSourceProperty();BeanUtils.copyProperties(sqlserver,dataSourceProperty);DataSource sqlserverDataSource = hikariDataSourceCreator.createDataSource(dataSourceProperty);DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;Set<String> dataSourceSet = ds.getCurrentDataSources().keySet();if (!dataSourceSet.contains(sqlserver.getDataSourceName())) {ds.addDataSource(sqlserver.getDataSourceName(),sqlserverDataSource);}//push 设置当前线程数据源 如非必要不要手动调用,调用后确保最终清除DynamicDataSourceContextHolder.push(sqlserver.getDataSourceName());List<SUser> sUsers = sUserMapper.selectList(new LambdaQueryWrapper<>());System.out.println(sUsers);//DynamicDataSourceContextHolder.poll();//poll 清空当前线程数据源 如果当前线程是连续切换数据源 只会移除掉当前线程的数据源名称//clear 强制清空本地线程  防止内存泄漏,如手动调用了push可调用此方法确保清除DynamicDataSourceContextHolder.clear();ds.removeDataSource(sqlserver.getDataSourceName());}else {System.out.println("数据源连接异常");}}

这里一定要对数据源可用性进行校验,确保可用才进行数据源添加和切换当前数据源操作

其中SUser是Sqlserver中新建表对应的实体类

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "s_user")
public class SUser implements Serializable {private static final long serialVersionUID = -5514139686858156155L;private Integer id;private String name;private Integer age;private String address;}

调用查询的mapper接口实现

import com.badao.demo.entity.SUser;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;@Repository
public interface SUserMapper extends BaseMapper<SUser> {}

单元测试运行结果

7、将以上手动切换数据源和执行业务逻辑的操作封装成工具类

import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import java.util.function.Supplier;/*** 数据源切换工具类*/
public class DynamicDSExecute {public static <T> T execute(String dsName, Supplier<T> executor){try {DynamicDataSourceContextHolder.push(dsName);return executor.get();}finally {DynamicDataSourceContextHolder.clear();}}
}

这里用到了函数式接口,可参考如下

java8中常用函数式接口Supplier<T>、Consumer<T>、Function<T,R>、Predicate<T>使用示例:

java8中常用函数式接口Supplier<T>、Consumer<T>、Function<T,R>、Predicate<T>使用示例_java8 函数式编程supplier接口案例大全-CSDN博客

然后调用工具类时

            Supplier<List<SUser>> supplier = () -> sUserMapper.selectList(new LambdaQueryWrapper<>());List<SUser> sUsers = DynamicDSExecute.execute(sqlserver.getDataSourceName(),supplier);

这篇关于SpringBoot+dynamic-datasource实现多数据源(msyql、sqlserver、postgresql)手动切换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/627277

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

SQL中的外键约束

外键约束用于表示两张表中的指标连接关系。外键约束的作用主要有以下三点: 1.确保子表中的某个字段(外键)只能引用父表中的有效记录2.主表中的列被删除时,子表中的关联列也会被删除3.主表中的列更新时,子表中的关联元素也会被更新 子表中的元素指向主表 以下是一个外键约束的实例展示

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

如何去写一手好SQL

MySQL性能 最大数据量 抛开数据量和并发数,谈性能都是耍流氓。MySQL没有限制单表最大记录数,它取决于操作系统对文件大小的限制。 《阿里巴巴Java开发手册》提出单表行数超过500万行或者单表容量超过2GB,才推荐分库分表。性能由综合因素决定,抛开业务复杂度,影响程度依次是硬件配置、MySQL配置、数据表设计、索引优化。500万这个值仅供参考,并非铁律。 博主曾经操作过超过4亿行数据