springboot动态数据源【非伪数据源】

说明:本文章的数据源不是在配置文件中配置两个或多个数据源,在业务方面对这些数据源来回切换,本文章中的数据源是可以动态添加,修改,切换的,废话不多说。

先看工程图:springboot动态数据源【非伪数据源】_第1张图片

1.pom.xml文件



  4.0.0

  com.example
  demo
  0.0.1-SNAPSHOT
  jar

  DemoOne
  Demo project for Spring Boot

  
    org.springframework.boot
    spring-boot-starter-parent
    2.2.2.RELEASE
     
  

  
    UTF-8
    UTF-8
    1.2.0
    5.1.39
    1.8
  

  

    
    
      org.springframework.boot
      spring-boot-starter-web
    
    
      org.springframework.boot
      spring-boot-starter-validation
    
    
      org.springframework.boot
      spring-boot-starter-freemarker
    
    
      org.springframework.boot
      spring-boot-starter-test
      test
    

    
    
      mysql
      mysql-connector-java
      runtime
    

    
    
      com.oracle
      ojdbc6
      11.2.0.3
    

    
    
      org.postgresql
      postgresql
      42.2.2
    

    
    
      com.baomidou
      dynamic-datasource-spring-boot-starter
      3.5.1
    
    
      com.alibaba
      druid-spring-boot-starter
      1.2.9
    
    
      com.baomidou
      mybatis-plus-boot-starter
      3.5.1
    
    
      com.baomidou
      mybatis-plus-generator
      3.5.2
    
    
      org.apache.commons
      commons-dbcp2
      2.8.0
    

    
    
      com.github.pagehelper
      pagehelper-spring-boot-starter
      
        
          mybatis
          org.mybatis
        
        
          mybatis-spring
          org.mybatis
        
      
      1.2.10
    


    
      com.h2database
      h2
    
    
    
      org.projectlombok
      lombok
      1.14.8
    

    
    
      com.github.xiaoymin
      knife4j-spring-boot-starter
      2.0.9
    

    
    
      cn.hutool
      hutool-all
      5.8.0.M3
    

    
    
      commons-lang
      commons-lang
      2.6
    

    
    
      com.google.guava
      guava
      21.0
    

    
    
      com.alibaba
      fastjson
      1.2.28
    



  

  
    
      
        org.springframework.boot
        spring-boot-maven-plugin
      
    
  

2.application.yml

server:
  port: 9000
spring:
  datasource:
    dynamic:
      primary: master
      datasource:
        #默认数据库
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://127.0.0.1:3306/my_demo_01?characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
          username: root
          password: root
        #my_demo_02:
        #  driver-class-name: com.mysql.cj.jdbc.Driver
        #  url: jdbc:mysql://127.0.0.1:3306/my_demo_02?characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
        #  username: root
        #  password: root

  jackson:
    date-format: dd/MM/yyyy
    time-zone: GMT+8
  mvc:
    date-format: dd/MM/yyyy HH:mm:ss
    pathmatch:
      matching-strategy: ant_path_matcher
logging:
  level:
    com.baomidou: debug
mybatis-plus:
  mapper-locations: classpath:mappers/*.xml
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.fs_order.sql和sys_user.sql

/*
 Navicat Premium Data Transfer

 Source Server         : 本机数据库mysql
 Source Server Type    : MySQL
 Source Server Version : 80011 (8.0.11)
 Source Host           : localhost:3306
 Source Schema         : my_demo_01

 Target Server Type    : MySQL
 Target Server Version : 80011 (8.0.11)
 File Encoding         : 65001

 Date: 30/10/2023 11:24:09
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '主键',
  `user_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '用户名',
  `nick_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '昵称',
  `age` int(4) NULL DEFAULT NULL COMMENT '年龄',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES ('a', 'zhanglong', '张龙', 30);
INSERT INTO `sys_user` VALUES ('b', 'zhaohu', '赵虎', 31);
INSERT INTO `sys_user` VALUES ('c', 'wangchao', '王朝', 32);
INSERT INTO `sys_user` VALUES ('d', 'mahan', '马汉', 33);

SET FOREIGN_KEY_CHECKS = 1;
/*
 Navicat Premium Data Transfer

 Source Server         : 本机数据库mysql
 Source Server Type    : MySQL
 Source Server Version : 80011 (8.0.11)
 Source Host           : localhost:3306
 Source Schema         : my_demo_02

 Target Server Type    : MySQL
 Target Server Version : 80011 (8.0.11)
 File Encoding         : 65001

 Date: 30/10/2023 11:24:22
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for fs_order
-- ----------------------------
DROP TABLE IF EXISTS `fs_order`;
CREATE TABLE `fs_order`  (
  `id` varchar(38) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `order_num` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '订单号',
  `address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '订单地址',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '订单表' ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of fs_order
-- ----------------------------
INSERT INTO `fs_order` VALUES ('111', '0456afa8-3c7b-40a6-a82c-544ea16ee082', '梁山八百里水泊');
INSERT INTO `fs_order` VALUES ('222', '625b2fa6-a3c5-49f9-bfc9-f8c84b5af6a0', '大运河桥');

SET FOREIGN_KEY_CHECKS = 1;

4.MySpringBootApplication.java

package com.example;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

//@MapperScan("com.example.mapper")  //在数据层配置@Mapper一个功能
@SpringBootApplication
public class MySpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }
}

5.SwaggerConfig.java

package com.example.config;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.util.ArrayList;
import java.util.List;


/**
 * @author 李庆伟
 * @date 2022/5/20 10:22
 */
@ConditionalOnWebApplication
@Configuration
@EnableSwagger2WebMvc
@EnableKnife4j
public class SwaggerConfig {

    /**
     * Swagger2的配置文件,这里可以配置Swagger2的一些基本的内容,比如扫描的包等等
     * []
     * @return {@link Docket}
     * @throws
     * @author 李庆伟
     * @date 2021/12/13 16:28
     */
    @Bean
    public Docket createRestApi() {
        //设置请求在父类方法中,如果在本类方法中设置请求头,则覆盖父类方法
        List pars = makeHeader();
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage(makeScan()))
                //.apis(RequestHandlerSelectors.basePackage(App8300.class.getPackage().getName()))
                .build()
                .globalOperationParameters(pars)
                .apiInfo(apiInfo());
    }

    /**
     * swagger封装请求头
     * [pars]
     * @return {@link List< Parameter>}
     * @throws
     * @author 李庆伟
     * @date 2022/5/20 11:26
     */
    public List makeHeader(){
        List pars = new ArrayList<>();
        ParameterBuilder token = new ParameterBuilder();
        token.name("Authorization").description("Authorization")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false).build();
        pars.add(token.build());

        ParameterBuilder languageCode = new ParameterBuilder();
        languageCode.name("languageCode").description("languageCode")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .required(false).build();
        pars.add(languageCode.build());

        return pars;
    }

    public String makeScan(){
        return "com.example.controller";
    }


    /**
     * 构建API文档的详细信息函数
     * @return
     */
    public ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title(makeApiName())
                .version("1.0")
                .build();
    }

    public String makeApiName(){
        return "项目接口 API";
    }



}

6.Result.java

package com.example.results;

import com.alibaba.fastjson.JSON;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.servlet.ServletResponse;
import java.io.PrintWriter;
import java.util.List;

/**
 * @author 李庆伟
 * @date 2020/4/16 9:52
 */
@Data
public class Result {

    @ApiModelProperty(value = "返回码")
    private int code;

    @ApiModelProperty(value = "返回数据")
    private Object data;

    @ApiModelProperty(value = "返回描述")
    private String msg;

    @ApiModelProperty(value = "返回长度")
    private long count;

    @ApiModelProperty(value = "详细信息")
    private String detailMessage;

    /**返回成功 */
    public static Result success(List data, long count){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功!");//提示语
        result.setData(data);
        result.setCount(count);
        return result;
    }

    /**返回成功 */
    public static Result success(List data){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功!");//提示语
        result.setData(data);
        result.setCount(data == null || data.size() == 0 ? 0 : data.size());
        return result;
    }

    /**返回成功 */
    public static Result successForPage(List data,Integer count){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("失败!");//提示语
        result.setData(data);
        result.setCount(count == null ? 0 : count);
        return result;
    }

    /**返回成功 */
    public static Result success(){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功!");//提示语
        return result;
    }

    /**返回成功 */
    public static Result success(Object object){
        Result result = new Result();
        result.setCode(0);//成功
        result.setMsg("成功!");//提示语
        result.setData(object);//返回内容
        return result;
    }

    /**返回失败 */
    public static Result error(){
        Result result = new Result();
        result.setCode(1);//失败
        result.setMsg("失败!");//提示语
        return result;
    }

    /**返回失败 */
    public static Result error(int code, String msg){
        Result result = new Result();
        result.setCode(code);//失败
        result.setMsg("失败!");//提示语
        return result;
    }

    /**返回失败 */
    public static Result error(int code, String msg, String detailMessage){
        Result result = new Result();
        result.setCode(code);//失败
        result.setMsg("失败!");//提示语
        result.setDetailMessage(detailMessage);
        return result;
    }

    /**Response输出Json格式 */
    public static void responseJson(ServletResponse response, Object data) {
        PrintWriter out = null;
        try {
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/json");
            out = response.getWriter();
            out.println(JSON.toJSONString(data));
            out.flush();
        } catch (Exception e) {
            System.out.println("Response输出Json异常:" + e);
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }
	/**返回信息*/
	public static Result response(int code, String msg, Object data) {
		Result result = new Result();
		result.setCode(code);
		result.setMsg(msg);
		result.setData(data);
		return result;
	}
}

7.DbDataSourceConstant.java

package com.example.constant;

/**
 * @Description: TODO
 * @param:
 * @return: {@link }
 * @throws:
 * @author:李庆伟
 * @date: 2023/10/27 14:09
 */
public class DbDataSourceConstant {

    //oracle 驱动名称
    public static final String ORACLE_DRIVER_CLASS_NAME = "oracle.jdbc.driver.OracleDriver";

    //mysql 低版本驱动名称(6.0以下)
    public static final String MYSQL_LOW_DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver";

    //mysql 高版本驱动名称(6.0以上)
    public static final String MYSQL_HIGH_DRIVER_CLASS_NAME = "com.mysql.cj.jdbc.Driver";

    //psotgresql 驱动名称
    public static final String PSOTGRESQL_HIGH_DRIVER_CLASS_NAME = "org.postgresql.Driver";
}

8.DbOprUtil.java

package com.example.utils;

import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DefaultDataSourceCreator;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.example.constant.DbDataSourceConstant;
import com.example.dto.DbDataSourceDTO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Set;

/**
 * @Description: 操作数据源工具类
 * @param:
 * @return: {@link }
 * @throws:
 * @author:李庆伟
 * @date: 2023/6/30 17:14
 */
@Component
public class DbOprUtil {

    @Autowired
    private DataSource dataSource;
    @Resource
    private DefaultDataSourceCreator dataSourceCreator;


    /**
     * @Description: 添加数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/6/30 17:21
     */
    public Set addDataSource(DbDataSourceDTO sourceDTO) {
        // 根据数据库类型设置驱动名称
        switch (sourceDTO.getType().toLowerCase()) {
            case "mysql":
                sourceDTO.setDriverClassName(DbDataSourceConstant.MYSQL_HIGH_DRIVER_CLASS_NAME);
                break;
            case "oracle":
                sourceDTO.setDriverClassName(DbDataSourceConstant.ORACLE_DRIVER_CLASS_NAME);
                break;
            case "postgresql":
                sourceDTO.setDriverClassName(DbDataSourceConstant.PSOTGRESQL_HIGH_DRIVER_CLASS_NAME);
                break;
            default:
                return null;
        }
        boolean status = DbLinkUtil.verifyUrlConnStatus(sourceDTO.getUrl(), sourceDTO.getDriverClassName(), sourceDTO.getUsername(), sourceDTO.getPassword());
        if (!status) {
            throw new RuntimeException("数据源链接失败!");
        }
        DataSourceProperty dataSourceProperty = new DataSourceProperty();
        BeanUtils.copyProperties(sourceDTO, dataSourceProperty);
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        DataSource dataSource = dataSourceCreator.createDataSource(dataSourceProperty);
        try {
            Connection connection = dataSource.getConnection();
            //String schema = connection.getSchema();
            ///System.err.println(schema);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // 添加数据源
        ds.addDataSource(sourceDTO.getPoolName(), dataSource);
        return ds.getDataSources().keySet();
    }

    /**
     * @Description: 获取所以数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/6/30 17:22
     */
    public Set getAllDataSource() {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        return ds.getDataSources().keySet();
    }
    public DynamicRoutingDataSource getDataSource() {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        return ds;
    }

    /**
     * @Description: 根据数据源名称删除数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/6/30 17:22
     */
    public void removeByDataSourceByName(String dataSourceName) {
        DynamicRoutingDataSource ds = (DynamicRoutingDataSource) dataSource;
        ds.removeDataSource(dataSourceName);
    }

    /**
     * @Description: 手动切换到该数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/6/30 17:22
     */
    public void changeByDataSourceByName(String dataSourceName) {
        Set set = getAllDataSource();
        if(set != null && set.size() > 0 && set.contains(dataSourceName)){
            DynamicDataSourceContextHolder.push(dataSourceName);
        } else {
            throw new RuntimeException("数据源链接切换失败!");
        }
    }




}

9.DbLinkUtil.java

package com.example.utils;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

/**
 * @Description: 校验数据源连接是否成功
 * @param:
 * @return: {@link }
 * @throws:
 * @author:李庆伟
 * @date: 2023/6/30 17:14
 */
public class DbLinkUtil {

    /**
     * @Description: 校验数据源连接是否成功,不成功抛异常
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/27 14:37
     */
    public static boolean verifyUrlConnStatus(String url,String driverClassName, String username, String password) {

        boolean flag;
        Connection connection = null;
        // 加载驱动类
        try {
            Class.forName(driverClassName);
            connection = DriverManager.getConnection(url, username, password);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("数据源链接不存在!");
        }finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return flag;
    }

    /**
     * @Description: 校验数据源连接是否成功,不成功返回false
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/27 14:37
     */
    public static boolean verifyUrlConnStatusForB(String url,String driverClassName, String username, String password) {

        boolean flag;
        Connection connection = null;
        // 加载驱动类
        try {
            Class.forName(driverClassName);
            connection = DriverManager.getConnection(url, username, password);
            flag = true;
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
        }finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        return flag;
    }
}

10.DataSourceController.java

package com.example.controller;

import com.example.dto.DbDataSourceDTO;
import com.example.results.Result;
import com.example.service.DataSourceService;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:32
 */
@RestController
@RequestMapping("/operDb")
@Api(tags = "数据源操作")
public class DataSourceController {

    @Autowired
    private DataSourceService dataSourceService;

    /**
     * @Description: 数据源分页查询
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/7/7 14:36
     */
    @PostMapping(value = "find")
    @ApiOperation(value = "查询所有数据源",notes = "查询所有数据源")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= DbDataSourceDTO.class),
    })
    public Result find() {
        List result = dataSourceService.find();
        return Result.success(result);
    }

    /**
     * @Description: 添加数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/7/7 15:31
     * 以下面数据为例:
     * poolName:my_demo_02
     * type:mysql
     * driverClassName:com.mysql.cj.jdbc.Driver
     * url:jdbc:mysql://127.0.0.1:3306/my_demo_02?characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
     * username:root
     * password:root
     */
    @PostMapping(value = "/add")
    @ApiOperation(value = "添加数据源", notes = "添加数据源", produces = "application/json")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= DbDataSourceDTO.class),
    })
    public Result add(@Valid DbDataSourceDTO form) {
        dataSourceService.add(form);
        return Result.success();
    }

    /**
     * @Description: 测试数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/7/7 15:31
     */
    @PostMapping(value = "/checked")
    @ApiOperation(value = "测试数据源", notes = "测试数据源", produces = "application/json")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= DbDataSourceDTO.class),
    })
    public Result checked(@Valid DbDataSourceDTO form) {
        dataSourceService.checked(form);
        return Result.success();
    }

    /**
     * @Description: 修改数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/7/10 15:44
     */
    @PostMapping(value = "/edit")
    @ApiOperation(value = "修改数据源", notes = "修改数据源", produces = "application/json")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= DbDataSourceDTO.class),
    })
    public Result edit(@Valid DbDataSourceDTO form) {
        dataSourceService.update(form);
        return Result.success();
    }

    /**
     * @Description: 删除数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/7/10 15:54
     */
    @PostMapping(value = "/delete")
    @ApiOperation(value = "删除数据源", notes = "删除数据源", produces = "application/json")
    public Result delete(DbDataSourceDTO form) {
        dataSourceService.delete(form);
        return Result.success();
    }



}

11.DataSourceService.java

package com.example.service;

import com.example.dto.DbDataSourceDTO;

import java.util.List;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:41
 */
public interface DataSourceService {

    //查询所有数据源
    List find();

    //添加数据源
    void add(DbDataSourceDTO form);

    //测试数据源是否能连接上
    void checked(DbDataSourceDTO form);

    //修改数据源
    void update(DbDataSourceDTO form);

    //删除数据源
    void delete(DbDataSourceDTO form);

}

12.DataSourceServiceImpl.java

package com.example.service.impl;

import com.example.constant.DbDataSourceConstant;
import com.example.dto.DbDataSourceDTO;
import com.example.service.DataSourceService;
import com.example.utils.DbLinkUtil;
import com.example.utils.DbOprUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:41
 */
@Service
public class DataSourceServiceImpl implements DataSourceService {


    @Autowired
    private DbOprUtil dbOprUtil;

    /**
     * @Description: 获取所有数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 9:52
     */
    @Override
    public List find() {
        Set st = dbOprUtil.getAllDataSource();
        List list = new ArrayList<>();
        if(st != null && st.size() > 0){
            for (String str : st) {
                DbDataSourceDTO dbDataSourceDTO = new DbDataSourceDTO();
                dbDataSourceDTO.setPoolName(str);
                //数据源连接等信息在这里就不获取了,自己debug去找,里面都有
                list.add(dbDataSourceDTO);
            }
        }
        return list;
    }

    /**
     * @Description: 添加数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 9:52
     */
    @Override
    public void add(DbDataSourceDTO form) {
        //验证数据源是否可用
        checked(form);

        //添加到源中成功后 在添加到数据源库中

        //如果成功 Add到数据源中
        dbOprUtil.addDataSource(form);
    }

    /**
     * @Description: 验证数据源是否可用
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 9:53
     */
    @Override
    public void checked(DbDataSourceDTO form) {
        //master为系统初始化数据源名称,不能被其他数据源替代和删除
        if(form != null && StringUtils.isNotEmpty(form.getPoolName()) && "master".equals(form.getPoolName().toLowerCase())){
            throw new RuntimeException("该关键字不能作为名称使用");
        }
        switch (form.getType().toLowerCase()) {
            case "mysql":
                form.setDriverClassName(DbDataSourceConstant.MYSQL_HIGH_DRIVER_CLASS_NAME);
                break;
            case "oracle":
                form.setDriverClassName(DbDataSourceConstant.ORACLE_DRIVER_CLASS_NAME);
                break;
            case "postgresql":
                form.setDriverClassName(DbDataSourceConstant.PSOTGRESQL_HIGH_DRIVER_CLASS_NAME);
                break;
            default:
                form.setDriverClassName("");
        }
        //判断数据源连接是否能够连接成功
        DbLinkUtil.verifyUrlConnStatus(form.getUrl(),form.getDriverClassName(),form.getUsername(),form.getPassword());

    }

    /**
     * @Description: 修改数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 9:53
     */
    @Override
    public void update(DbDataSourceDTO form) {
        //验证数据源是否可用
        checked(form);
        //修改数据源库中存储数据源

        //删除已有数据源
        delete(form);

        //如果成功 Add到数据源中
        dbOprUtil.addDataSource(form);
    }

    /**
     * @Description: 删除数据源
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 9:53
     */
    @Override
    public void delete(DbDataSourceDTO form) {
        if(!form.getPoolName().equals("master")){
            dbOprUtil.removeByDataSourceByName(form.getPoolName());
        }
    }

}

13.FsOrder.java

package com.example.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 类名称:订单
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:26
 */
@Data
@TableName
public class FsOrder {

    @TableId
    private String id;

    private String orderNum;//订单号

    private String address;//订单地址
}

14.SysUser.java

package com.example.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 类名称:用户
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:26
 */
@Data
@TableName
public class SysUser {

    @TableId
    private String id;

    private String userName;//用户名

    private String nickName;//昵称

    private Integer age;//年龄
}

15.TestController.java

package com.example.controller;

import com.example.entity.FsOrder;
import com.example.entity.SysUser;
import com.example.results.Result;
import com.example.service.TestService;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:32
 */
@RestController
@RequestMapping("/test")
@Api(tags = "测试通过动态数据源查询数据")
public class TestController {

    @Autowired
    private TestService testService;

    /**
     * @Description: 查询所有用户【在master数据库中】
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 10:58
     *
     */
    @PostMapping(value = "findAllSysUser")
    @ApiOperation(value = "查询所有用户【在master数据库中】",notes = "查询所有用户【在master数据库中】")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= Result.class),
    })
    public Result findAllSysUser() {
        List result = testService.findAllSysUser();
        return Result.success(result);
    }

    /**
     * @Description: 查询所有的订单【在my_demo_02数据库中】
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 10:58
     *
     * 以下面数据为例:先添加下面为例子的数据源(调用DataSourceController中的add方法,可以在swagger中做,这里就不多说了)
     * poolName:my_demo_02
     * type:mysql
     * driverClassName:com.mysql.cj.jdbc.Driver
     * url:jdbc:mysql://127.0.0.1:3306/my_demo_02?characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8
     * username:root
     * password:root
     */
    @PostMapping(value = "findAllFsOrder")
    @ApiOperation(value = "查询所有订单【在my_demo_02数据库中】",notes = "查询所有订单【在my_demo_02数据库中】")
    @ApiResponses({
            @ApiResponse(code = 0, message = "ok", response= Result.class),
    })
    public Result findAllFsOrder() {
        List result = testService.findAllFsOrder();
        return Result.success(result);
    }

}

16.TestService.java

package com.example.service;

import com.example.entity.FsOrder;
import com.example.entity.SysUser;

import java.util.List;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月30日 11:02
 */
public interface TestService {

    //查询所有的用户 【在master数据库中】
    List findAllSysUser();

    //查询所有的订单【在my_demo_02数据库中】
    List findAllFsOrder();
}

17.TestServiceImpl.java

package com.example.service.impl;

import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.entity.FsOrder;
import com.example.entity.SysUser;
import com.example.mapper.FsOrderMapper;
import com.example.mapper.SysUserMapper;
import com.example.service.TestService;
import com.example.utils.DbOprUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;

/**
 * 类名称:
 *
 * @author 李庆伟
 * @date 2023年10月30日 11:02
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private DbOprUtil dbOprUtil;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private FsOrderMapper fsOrderMapper;

    /**
     * @Description: 查询所有的用户 【在master数据库中】
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 11:04
     */
    @Override
    public List findAllSysUser() {
        //切换为master数据源,master为DbDataSourceDTO中的poolName(连接池名称:自定义不能重)
        dbOprUtil.changeByDataSourceByName("master");
        return sysUserMapper.selectList(new QueryWrapper());
    }

    /**
     * @Description: 查询所有的订单【在my_demo_02数据库中】
     * @param:
     * @return: {@link }
     * @throws:
     * @author:李庆伟
     * @date: 2023/10/30 11:04
     */
    @Override
    public List findAllFsOrder() {
        //切换为my_demo_02数据源,my_demo_02为DbDataSourceDTO中的poolName(连接池名称:自定义不能重)
        dbOprUtil.changeByDataSourceByName("my_demo_02");
        return fsOrderMapper.selectList(new QueryWrapper());
    }


    //@DSTransactional//多数据源事务注解
    //public void save() {
    //    dbOprUtil.changeByDataSourceByName("master");
    //    //insert master对应库数据
    //    //业务就省略了
    //    dbOprUtil.changeByDataSourceByName("my_demo_02");
    //    //insert my_demo_02对应库数据
    //    //业务就省略了
    //}
}

18.FsOrderMapper.java

package com.example.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 类名称:订单
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:26
 */
@Data
@TableName
public class FsOrder {

    @TableId
    private String id;

    private String orderNum;//订单号

    private String address;//订单地址
}

19.SysUser.java

package com.example.entity;

import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 类名称:用户
 *
 * @author 李庆伟
 * @date 2023年10月27日 15:26
 */
@Data
@TableName
public class SysUser {

    @TableId
    private String id;

    private String userName;//用户名

    private String nickName;//昵称

    private Integer age;//年龄
}

20.测试看效果:http://localhost:9000/doc.html

 动态数据源添加

springboot动态数据源【非伪数据源】_第2张图片

 数据源查询

springboot动态数据源【非伪数据源】_第3张图片

 不同数据源下的表数据查询

springboot动态数据源【非伪数据源】_第4张图片

springboot动态数据源【非伪数据源】_第5张图片

记录一点点。。。。。。。。。。。。。。。

你可能感兴趣的:(Java,spring,boot,spring,mybatis,java)