当前位置: 首页 > news >正文

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

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

先看工程图:

1.pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>DemoOne</name><description>Demo project for Spring Boot</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.2.RELEASE</version><relativePath/> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><mybatis-spring-boot.version>1.2.0</mybatis-spring-boot.version><mysql-connector.version>5.1.39</mysql-connector.version><java.version>1.8</java.version></properties><dependencies><!--springboot相关包--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- MySQL依赖导入 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- Oracle依赖导入 --><dependency><groupId>com.oracle</groupId><artifactId>ojdbc6</artifactId><version>11.2.0.3</version></dependency><!-- postgresql依赖导入 --><dependency><groupId>org.postgresql</groupId><artifactId>postgresql</artifactId><version>42.2.2</version></dependency><!--mybatis-plus相关依赖导入--><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.5.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.9</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.2</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-dbcp2</artifactId><version>2.8.0</version></dependency><!-- pagehelper分页 依赖导入--><dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-starter</artifactId><exclusions><exclusion><artifactId>mybatis</artifactId><groupId>org.mybatis</groupId></exclusion><exclusion><artifactId>mybatis-spring</artifactId><groupId>org.mybatis</groupId></exclusion></exclusions><version>1.2.10</version></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId></dependency><!--get set 依赖导入--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.14.8</version></dependency><!-- knife4j 增强swagger依赖导入 --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>2.0.9</version></dependency><!-- hutool 工具包依赖导入 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.0.M3</version></dependency><!--StringUtils工具包依赖导入--><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency><!--字符串转驼峰依赖导入--><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>21.0</version></dependency><!--josn依赖导入--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.28</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

2.application.yml

server:port: 9000
spring:datasource:dynamic:primary: masterdatasource:#默认数据库master:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/my_demo_01?characterEncoding=utf8&useSSL=false&autoReconnect=true&allowPublicKeyRetrieval=true&serverTimezone=GMT%2B8username: rootpassword: 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: rootjackson:date-format: dd/MM/yyyytime-zone: GMT+8mvc:date-format: dd/MM/yyyy HH:mm:sspathmatch:matching-strategy: ant_path_matcher
logging:level:com.baomidou: debug
mybatis-plus:mapper-locations: classpath:mappers/*.xmlconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.fs_order.sql和sys_user.sql

/*Navicat Premium Data TransferSource Server         : 本机数据库mysqlSource Server Type    : MySQLSource Server Version : 80011 (8.0.11)Source Host           : localhost:3306Source Schema         : my_demo_01Target Server Type    : MySQLTarget Server Version : 80011 (8.0.11)File Encoding         : 65001Date: 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 TransferSource Server         : 本机数据库mysqlSource Server Type    : MySQLSource Server Version : 80011 (8.0.11)Source Host           : localhost:3306Source Schema         : my_demo_02Target Server Type    : MySQLTarget Server Version : 80011 (8.0.11)File Encoding         : 65001Date: 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*/@Beanpublic Docket createRestApi() {//设置请求在父类方法中,如果在本类方法中设置请求头,则覆盖父类方法List<Parameter> 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<Parameter> makeHeader(){List<Parameter> 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<Object> 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 {@Autowiredprivate DataSource dataSource;@Resourceprivate DefaultDataSourceCreator dataSourceCreator;/*** @Description: 添加数据源* @param:* @return: {@link }* @throws:* @author:李庆伟* @date: 2023/6/30 17:21*/public Set<String> 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<String> 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<String> 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 {@Autowiredprivate 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<DbDataSourceDTO> 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<DbDataSourceDTO> 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 {@Autowiredprivate DbOprUtil dbOprUtil;/*** @Description: 获取所有数据源* @param:* @return: {@link }* @throws:* @author:李庆伟* @date: 2023/10/30 9:52*/@Overridepublic List<DbDataSourceDTO> find() {Set<String> st = dbOprUtil.getAllDataSource();List<DbDataSourceDTO> 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*/@Overridepublic void add(DbDataSourceDTO form) {//验证数据源是否可用checked(form);//添加到源中成功后 在添加到数据源库中//如果成功 Add到数据源中dbOprUtil.addDataSource(form);}/*** @Description: 验证数据源是否可用* @param:* @return: {@link }* @throws:* @author:李庆伟* @date: 2023/10/30 9:53*/@Overridepublic 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*/@Overridepublic void update(DbDataSourceDTO form) {//验证数据源是否可用checked(form);//修改数据源库中存储数据源//删除已有数据源delete(form);//如果成功 Add到数据源中dbOprUtil.addDataSource(form);}/*** @Description: 删除数据源* @param:* @return: {@link }* @throws:* @author:李庆伟* @date: 2023/10/30 9:53*/@Overridepublic 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 {@TableIdprivate 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 {@TableIdprivate 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 {@Autowiredprivate 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<SysUser> 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<FsOrder> 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<SysUser> findAllSysUser();//查询所有的订单【在my_demo_02数据库中】List<FsOrder> 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 {@Autowiredprivate DbOprUtil dbOprUtil;@Resourceprivate SysUserMapper sysUserMapper;@Resourceprivate FsOrderMapper fsOrderMapper;/*** @Description: 查询所有的用户 【在master数据库中】* @param:* @return: {@link }* @throws:* @author:李庆伟* @date: 2023/10/30 11:04*/@Overridepublic List<SysUser> findAllSysUser() {//切换为master数据源,master为DbDataSourceDTO中的poolName(连接池名称:自定义不能重)dbOprUtil.changeByDataSourceByName("master");return sysUserMapper.selectList(new QueryWrapper<SysUser>());}/*** @Description: 查询所有的订单【在my_demo_02数据库中】* @param:* @return: {@link }* @throws:* @author:李庆伟* @date: 2023/10/30 11:04*/@Overridepublic List<FsOrder> findAllFsOrder() {//切换为my_demo_02数据源,my_demo_02为DbDataSourceDTO中的poolName(连接池名称:自定义不能重)dbOprUtil.changeByDataSourceByName("my_demo_02");return fsOrderMapper.selectList(new QueryWrapper<FsOrder>());}//@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 {@TableIdprivate 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 {@TableIdprivate String id;private String userName;//用户名private String nickName;//昵称private Integer age;//年龄
}

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

 动态数据源添加

 数据源查询

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

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

相关文章:

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

说明&#xff1a;本文章的数据源不是在配置文件中配置两个或多个数据源&#xff0c;在业务方面对这些数据源来回切换&#xff0c;本文章中的数据源是可以动态添加&#xff0c;修改&#xff0c;切换的&#xff0c;废话不多说。 先看工程图&#xff1a; 1.pom.xml文件 <?x…...

如何改善设备综合效率(OEE)并提高工厂的生产力

在现代制造业中&#xff0c;提高设备综合效率&#xff08;Overall Equipment Efficiency&#xff0c;OEE&#xff09;是企业追求高效生产和优化生产能力的重要目标之一。OEE是一个关键的绩效指标&#xff0c;可以帮助企业评估设备的利用效率、生产效率和质量水平。本文将从三个…...

一文接入Android阿里Sophix热更新

最近公司项目渐趋成熟&#xff0c;已经不需要经常更新版本&#xff0c;并且更新版本对客户的影响特别大&#xff0c;但是日常维护难免需要更新代码&#xff0c;因此热修复的技术&#xff0c;就比较迫切了。 经过一段时间的对比&#xff0c;我们最终决定使用阿里的Sophix方案&am…...

【高阶数据结构】并查集和图

目录 1.数据结构--并查集 2.数据结构--图 1.图的基础概念 2.图的简单实现 2.1.邻接矩阵的图实现 2.2.邻接表的图实现 2.3.图的DFS和BFS 2.4.最小生成树 2.4.1.Kruskal(克鲁斯卡尔算法) 2.4.2.Prim&#xff08;普里姆算法&#xff09; 2.5.最短路径 2.5.1.Dijkstra(…...

Git 提交时提示 GPG 签名错误

本来应该一切都是正常的&#xff0c;但今天提交的时候提示 GPG 签名错误。 错误的信息就是 GPG 签名失败。 gpg: skipped "942395299055675C": No secret key gpg: signing failed: No secret key error: gpg failed to sign the data fatal: failed to write commi…...

vite+vue3实现 tomcat 的本地部署

背景&#xff1a; 很多开发小伙伴在本地开发完前端项目后&#xff0c;碍于服务端环境配置麻烦&#xff0c;想先试试在本地部署&#xff0c;已开发好的前端项目&#xff0c;由于很多文章都是文字性描述&#xff0c;不太直观&#xff0c;为了给大多数新手提供一个教程&#xff0c…...

docker+playwright

windows10 docker playwright 难点在于windows下docker的安装&#xff0c;以及官方hub被墙的困难。 wsl2 wsl2 ubuntu docker git clone https://gitee.com/lineuman/lcs_playwright.git npm install npx playwright test docker端口怎么映射到主机上面&#xff1f; 设置重…...

php框架路由实现

在PHP中也有很多框架&#xff08;如Laravel、CodeIgniter&#xff09;提供了路由功能。下面是一个简单的PHP路由实现原理和示例代码&#xff1a; 路由实现原理&#xff1a; 客户端发起请求&#xff0c;请求的URL会被传递给Web服务器。Web服务器将请求传递给PHP解释器&#xff…...

在CentOS 7中手工打造和运行xml文件配置的Servlet,然后使用curl、浏览器、telnet等三种工具各自测试

下载Openjdk并配置环境变量 https://jdk.java.net/java-se-ri/11-MR2是官网下载Openjdk 11的地方。 sudo wget https://download.java.net/openjdk/jdk11.0.0.1/ri/openjdk-11.0.0.1_linux-x64_bin.tar.gz下载openjdk 11。 sudo mkdir -p /usr/openjdk11创建目录&#xff…...

单例模式.

目录 ♫什么是单例模式 ♫饿汉式单例模式 ♫懒汉式单例模式 ♫单例模式的线程安全问题 ♪原子性 ♪内存可见性与指令重排序 ♫什么是单例模式 单例模式是一种设计模式&#xff0c;通过巧用Java的现有语法&#xff0c;实现一个只能被创建一个实例的类&#xff0c;并提供一个全…...

2023年MathorCup高校数学建模挑战赛大数据挑战赛赛题浅析

比赛时长为期7天的妈杯大数据挑战赛如期开赛&#xff0c;为了帮助大家更好的选题&#xff0c;首先给大家带来赛题浅析&#xff0c;为了方便大家更好的选题。 赛道 A&#xff1a;基于计算机视觉的坑洼道路检测和识别 A题&#xff0c;图像处理类题目。这种题目的难度数模独一档…...

c++小惊喜——stringstream

当需要读取一行字符串时&#xff0c;我们通常会有将这个字符串分开的想法 #include<iostream> #include<sstream> using namespace std;int main() {string str;getline(cin, str);stringstream ssin(str);string s[10];int cnt 0;while (ssin >> s[cnt]) …...

ubuntu 18.04 编译安装flexpart 10.4(2023年) —— 筑梦之路

2023年10月29日 环境说明 操作系统版本&#xff1a;ubuntu 18.04 python版本&#xff1a;3.6.9 gcc版本&#xff1a;7.5.0 编译安装路径&#xff1a;/usr/local cmake: 3.10.2 所需要的源码包我已经打包放到我的资源。 2021年1月份已经写过一篇Ubuntu 编译安装的帖子F…...

深度学习(生成式模型)——DDIM:Denoising Diffusion Implicit Models

文章目录 前言为什么DDPM的反向过程与前向过程步数绑定DDIM如何减少DDPM反向过程步数DDIM的优化目标DDIM的训练与测试 前言 上一篇博文介绍了DDIM的前身DDPM。DDPM的反向过程与前向过程步数一一对应&#xff0c;例如前向过程有1000步&#xff0c;那么反向过程也需要有1000步&a…...

HashMap的遍历方式 -- 好几次差点记不起来总结了一下

public class HashMapDemo {public static void main(String[] args) {// 创建一个HashMap并添加一些键值对Map<String, Integer> hashMap new HashMap<>();hashMap.put("Alice", 25);hashMap.put("Bob", 30);hashMap.put("Charlie"…...

PostgreSQL 两表关联更新sql

PostgreSQL两表关联更新SQL如下&#xff1a; UPDATE user SET username ft.name, age ft.age FROM userinfo WHERE user.id ft.id; user 要更新的表 userinfo数据来源表...

R2R 的一些小tip

批次间控制器(Run-to-run Controller)&#xff0c;以应对高混合生产的挑战。将最优配方参数与各种工业特征相关联的模型是根据历史数据离线训练的。预测的最优配方参数在线用于调整工艺条件。 批次控制(R2R control)是一种先进的工艺控制技术&#xff0c;可在运行(如批次或晶圆…...

UML中类之间的六种主要关系

UML中类之间的六种主要关系: 继承&#xff08;泛化&#xff09;&#xff08;Inheritance、Generalization&#xff09;, 实现&#xff08;Realization&#xff09;&#xff0c;关联&#xff08;Association)&#xff0c;聚合&#xff08;Aggregation&#xff09;&#xff0c;组…...

机器学习-朴素贝叶斯之多项式模型

多项式模型&#xff1a; 记住一定用于离散的对象&#xff0c;不能是连续的 于高斯分布相反&#xff0c;多项式模型主要适用于离散特征的概率计算&#xff0c;切sklearn的多项式模型不接受输入负值 因为多项式不接受负值的输入&#xff0c;所以样本数据的特征为数值型数据&…...

下载的nginx证书转换成tomcat证书格式

1、下载的nginx证书格式 XXX.crt private.key 2、转换成JKS格式证书步骤 #crt格式证书转pem openssl x509 -in xxx.crt -out xxx.pem#先转成p12格式&#xff0c;此时注意&#xff0c;如果有别名&#xff0c;需要设置 openssl pkcs12 -export -in xxx.crt -inkey private.key…...

计算机毕业设计选题推荐-社区志愿者服务微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…...

ES6中数值扩展

目录 二进制和八进制表示法 Number.isFinite() Number.isNaN() Number.parseInt()和Number.parseFloat() Number.isInteger() Math.trunc() Math.sign() Math.cbrt()&#xff1a; Math.clz32()&#xff1a; Math.imul()&#xff1a; Math.fround()&#xff1a; ES6中…...

sql-50练习题11-15

sql-50练习题11-15 前言数据库表结构介绍学生表课程表成绩表教师表 1-1 查询没有学全所有课程的同学的信息1-2 查询至少有一门课与学号为01的同学所学相同的同学的信息1-3 查询和1号的同学学习的课程完全相同的其他同学的信息1-4 查询没学过张三老师讲授的任一门课程的学生姓名…...

【多线程面试题十九】、 公平锁与非公平锁是怎么实现的?

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a; 公平锁与非公平锁是怎么…...

3.4每日一题(变量可分离方程通解)

...

LabVIEW背景颜色设为和其他程序或图像中一样

LabVIEW背景颜色设为和其他程序或图像中一样 有时候LabVIEW背景色要和其他程序或者图片的颜色保持一致&#xff0c;如果要求不高可以大致设置一下。如果要求较高&#xff0c;那可以按照如下的方式。 先用PS打开标准图像&#xff0c;之后用吸管工具选择图像上中的点&#xff0…...

图表参考线,数据对比一目了然_三叠云

参考线 路径 仪表盘 >> 仪表盘设计 功能简介 新增「参考线」功能。 参考线是在单个图表组件中添加的一条水平虚线&#xff0c;也可以配置两条线形成的参考区间&#xff0c;它表示该水平线上纵坐标值的大小。 使用场景&#xff1a; 通过辅助线的设置&#xff0c;可…...

【深度学习】Transformer、GPT、BERT、Seq2Seq什么区别?

请看vcr&#xff1a;https://transformers.run/back/transformer/...

数据结构与算法之LRU: 实现 LRU 缓存算法功能 (Javascript版)

关于LRU缓存 LRU - Lease Recently Used 最近使用 如果内存优先&#xff0c;只缓存最近使用的&#xff0c;删除 ‘沉睡’ 数据 核心 api: get set 分析 使用哈希表来实现, O(1)必须是有序的&#xff0c;常用放在前面&#xff0c;沉睡放在后面, 即&#xff1a;有序&#xff0…...

Matlab | 基于二次谱提取地震数据的地震子波

本文通过地震数据二次谱求取地震子波谱&#xff0c;具体方法如下&#xff1a; MATLAB代码实现如下&#xff1a; function w SndSpecExtWavelet(x, M) % 功能&#xff1a;基于二次谱提取输入地震数据data的地震子波wavelet % Extracting Wavelet from Input Seismic Dat…...