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

Spring Boot 配置多数据源【最简单的方式】

Druid连接池 Spring Boot 配置多数据源【最简单的方式】

文章目录

      • Druid连接池 Spring Boot 配置多数据源【最简单的方式】
  • 0.前言
  • 1.基础介绍
  • 2.步骤
    • 2.1. 引入依赖
    • 2.2. 配置文件
    • 2.3. 核心源码
      • Druid数据源创建器
      • Druid配置项 DruidConfig
  • 3.示例项目
    • 3.1. pom
      • 3.1.1. 依赖版本定义
      • 3.1.2. 依赖版本管理
      • 3.1.3. pom依赖
    • 3.2. 源代码
      • 3.2.1. DruidApplication
      • 3.2.2. UserService
      • 3.2.2. UserServiceImpl
      • 3.2.3. UserMapper
      • 3.2.3. User
      • 3.2.4. UserDto
      • 3.2.5. UserController
      • 3.2.6. 示例sql
  • 4.参考文档

0.前言

看了网上好多关于Spring Boot 配置数据库 多数据源的文章,其实不用那么多重复造轮子,目前已经有了一个特别成熟的开源组件dynamic-datasource ,已经支持各种各样的场景,来满足你多数据源的需求,我大概整理了一下,希望对初学者有用。
在这里插入图片描述

1.基础介绍

本文我们使用 dynamic-datasource 多数据源组件实现在springboot 项目中快速集成多数据源。

  • 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。
  • 支持数据库敏感配置信息 加密 ENC()。
  • 支持每个数据库独立初始化表结构schema和数据库database。
  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。
  • 支持 自定义注解 ,需继承DS(3.2.0+)。
  • 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。
  • 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。
  • 提供 自定义数据源来源 方案(如全从数据库加载)。
  • 提供项目启动后 动态增加移除数据源 方案。
  • 提供Mybatis环境下的 纯读写分离 方案。
  • 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。
  • 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。
  • 提供 **基于seata的分布式事务方案。
  • 提供 本地多数据源事务方案。

2.步骤

2.1. 引入依赖

  • 1.引入依赖,具体版本参考你当前的项目依赖管理中添加dependencyManagement中统一管理
		<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency>
    1. 排除原生Druid的快速配置类。
      注意:v3.3.3及以上版本不用排除了。
      方法1. 利用注解排除
      @SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}

方法2. 利用配置排除
或者也可以使用这种方式在配置文件中排除

spring:autoconfigure:exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure

2.2. 配置文件

增加配置如下,下面为了方便期间使用h2数据库作为示例数据库,mysql和其他数据库请按正确的jdbc url
配置

spring:datasource:druid:stat-view-servlet:enabled: truelogin-username: adminlogin-password: 123456dynamic:lazy: true# 配置全局druid参数,请按需配置druid:initial-size: 5max-active: 8min-idle: 3max-wait: 1000validation-query: 'select 1'datasource:master:username: sapassword: "123456"url: jdbc:h2:mem:test;MODE=MySQLdriver-class-name: org.h2.Driverdruid:socketTimeout: 1111slave_1:username: sapassword: "123456"url: jdbc:h2:mem:test;MODE=MySQLdriver-class-name: org.h2.Driverdruid:initial-size: 6slave_2:username: sapassword: "123456"url: jdbc:h2:mem:test;MODE=MySQLdriver-class-name: org.h2.Driver

druid 的原生配置在dynamic-datasource都是实现了的,大家可以按需选择

spring:datasource:druid:stat-view-servlet:enabled: trueloginUsername: adminloginPassword: 123456dynamic:druid: #以下是支持的全局默认值initial-size:max-active:filters: stat # 注意这个值和druid原生不一致,默认启动了stat。 如果确定什么filter都不需要 这里填 ""...等等基本都支持wall:none-base-statement-allow:stat:merge-sql:log-slow-sql:slow-sql-millis: datasource:master:username: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://xx.xx.xx.xx:3306/dynamic?characterEncoding=utf8&useSSL=falsedruid: # 以下是独立参数,每个库可以重新设置initial-size: 20validation-query: select 1 FROM DUAL #比如oracle就需要重新设置这个public-key: #(非全局参数)设置即表示启用加密,底层会自动帮你配置相关的连接参数和filter,推荐使用本项目自带的加密方法。
#           ......# 生成 publickey 和密码,推荐使用本项目自带的加密方法。
# java -cp druid-1.1.10.jar com.alibaba.druid.filter.config.ConfigTools youpassword

2.3. 核心源码

多数据源组件核心源码解释

Druid数据源创建器


package com.baomidou.dynamic.datasource.creator.druid;import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.logging.CommonsLogFilter;
import com.alibaba.druid.filter.logging.Log4j2Filter;
import com.alibaba.druid.filter.logging.Log4jFilter;
import com.alibaba.druid.filter.logging.Slf4jLogFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.baomidou.dynamic.datasource.creator.DataSourceCreator;
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
import com.baomidou.dynamic.datasource.enums.DdConstants;
import com.baomidou.dynamic.datasource.exception.ErrorCreateDataSourceException;
import com.baomidou.dynamic.datasource.toolkit.DsStrUtils;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;import javax.sql.DataSource;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.*;/*** Druid数据源创建器* * 该类是一个实现了DataSourceCreator接口的类,提供了创建Druid数据源的方法。* * @since 2020/1/21*/
@Slf4j
@NoArgsConstructor
@AllArgsConstructor
public class DruidDataSourceCreator implements DataSourceCreator {// 配置参数列表private static final Set<String> PARAMS = new HashSet<>();// 从配置文件中复制配置信息的方法private static Method configMethod = null;static {fetchMethod();}static {// 设置Druid支持的连接参数PARAMS.add("defaultCatalog");PARAMS.add("defaultAutoCommit");PARAMS.add("defaultReadOnly");PARAMS.add("defaultTransactionIsolation");PARAMS.add("testOnReturn");PARAMS.add("validationQueryTimeout");PARAMS.add("sharePreparedStatements");PARAMS.add("connectionErrorRetryAttempts");PARAMS.add("breakAfterAcquireFailure");PARAMS.add("removeAbandonedTimeoutMillis");PARAMS.add("removeAbandoned");PARAMS.add("logAbandoned");PARAMS.add("queryTimeout");PARAMS.add("transactionQueryTimeout");PARAMS.add("timeBetweenConnectErrorMillis");PARAMS.add("connectTimeout");PARAMS.add("socketTimeout");}//    @Autowired(required = false)//    private ApplicationContext applicationContext;// Druid配置对象private DruidConfig gConfig;/*** Druid since 1.2.17 use 'configFromPropeties' to copy config* Druid < 1.2.17 use 'configFromPropety' to copy config* 根据Druid的版本选择从配置文件中复制配置信息的方法*/private static void fetchMethod() {Class<DruidDataSource> aClass = DruidDataSource.class;try {configMethod = aClass.getMethod("configFromPropeties", Properties.class);return;} catch (NoSuchMethodException ignored) {}try {configMethod = aClass.getMethod("configFromPropety", Properties.class);return;} catch (NoSuchMethodException ignored) {}throw new RuntimeException("Druid does not has 'configFromPropeties' or 'configFromPropety' method!");}/*** 创建Druid数据源。* * @param dataSourceProperty 数据源配置信息* @return 创建的Druid数据源对象*/@Overridepublic DataSource createDataSource(DataSourceProperty dataSourceProperty) {DruidDataSource dataSource = new DruidDataSource();dataSource.setUsername(dataSourceProperty.getUsername());dataSource.setPassword(dataSourceProperty.getPassword());dataSource.setUrl(dataSourceProperty.getUrl());dataSource.setName(dataSourceProperty.getPoolName());String driverClassName = dataSourceProperty.getDriverClassName();if (DsStrUtils.hasText(driverClassName)) {dataSource.setDriverClassName(driverClassName);}DruidConfig config = dataSourceProperty.getDruid();Properties properties = DruidConfigUtil.mergeConfig(gConfig, config);// 初始化Druid过滤器List<Filter> proxyFilters = this.initFilters(dataSourceProperty, properties.getProperty("druid.filters"));dataSource.setProxyFilters(proxyFilters);try {configMethod.invoke(dataSource, properties);} catch (Exception ignore) {}// 设置连接参数dataSource.setConnectProperties(config.getConnectionProperties());// 设置Druid内置properties不支持的参数for (String param : PARAMS) {DruidConfigUtil.setValue(dataSource, param, gConfig, config);}if (Boolean.FALSE.equals(dataSourceProperty.getLazy())) {try {dataSource.init();} catch (SQLException e) {throw new ErrorCreateDataSourceException("druid create error", e);}}返回创建的Druid数据源对象。return dataSource;}/*** 初始化Druid过滤器。* * @param dataSourceProperty 数据源配置信息* @param filters 过滤器列表* @return 初始化后的过滤器列表*/private List<Filter> initFilters(DataSourceProperty dataSourceProperty, String filters) {List<Filter> proxyFilters = new ArrayList<>(2);if (DsStrUtils.hasText(filters)) {String[] filterItems = filters.split(",");for (String filter : filterItems) {switch (filter) {case "stat":// 初始化Druid Stat过滤器proxyFilters.add(DruidStatConfigUtil.toStatFilter(dataSourceProperty.getDruid().getStat(), gConfig.getStat()));break;case "wall":// 初始化Druid Wall过滤器WallConfig wallConfig = DruidWallConfigUtil.toWallConfig(dataSourceProperty.getDruid().getWall(), gConfig.getWall());WallFilter wallFilter = new WallFilter();wallFilter.setConfig(wallConfig);proxyFilters.add(wallFilter);break;case "slf4j":// 初始化Druid Slf4j Log过滤器proxyFilters.add(DruidLogConfigUtil.initFilter(Slf4jLogFilter.class, dataSourceProperty.getDruid().getSlf4j(), gConfig.getSlf4j()));break;case "commons-log":// 初始化Druid Commons Log过滤器proxyFilters.add(DruidLogConfigUtil.initFilter(CommonsLogFilter.class, dataSourceProperty.getDruid().getCommonsLog(), gConfig.getCommonsLog()));break;case "log4j":// 初始化Druid Log4j过滤器proxyFilters.add(DruidLogConfigUtil.initFilter(Log4jFilter.class, dataSourceProperty.getDruid().getLog4j(), gConfig.getLog4j()));break;case "log4j2":// 初始化Druid Log4j2过滤器proxyFilters.add(DruidLogConfigUtil.initFilter(Log4j2Filter.class, dataSourceProperty.getDruid().getLog4j2(), gConfig.getLog4j2()));break;default:log.warn("dynamic-datasource current not support [{}]", filter);}}}// TODO: 从Spring容器中获取过滤器
//        if (this.applicationContext != null) {
//            for (String filterId : gConfig.getProxyFilters()) {
//                proxyFilters.add(this.applicationContext.getBean(filterId, Filter.class));
//            }
//        }return proxyFilters;}/*** 判断是否支持创建该类型的数据源。* * @param dataSourceProperty 数据源配置信息* @return 如果支持创建该类型的数据源则返回true,否则返回false*/@Overridepublic boolean support(DataSourceProperty dataSourceProperty) {Class<? extends DataSource> type = dataSourceProperty.getType();return type == null || DdConstants.DRUID_DATASOURCE.equals(type.getName());}
}

Druid配置项 DruidConfig

dynamic-datasource 多数据源组件,将Druid 的配置项进行了支持,目前支持以下这些

package com.baomidou.dynamic.datasource.creator.druid;import lombok.Getter;
import lombok.Setter;import java.util.*;/*** Druid参数配置** @author TaoYu* @since 1.2.0*/
@Getter
@Setter
public class DruidConfig {private Integer initialSize;private Integer maxActive;private Integer minIdle;private Integer maxWait;private Long timeBetweenEvictionRunsMillis;private Long timeBetweenLogStatsMillis;private Long keepAliveBetweenTimeMillis;private Integer statSqlMaxSize;private Long minEvictableIdleTimeMillis;private Long maxEvictableIdleTimeMillis;private String defaultCatalog;private Boolean defaultAutoCommit;private Boolean defaultReadOnly;private Integer defaultTransactionIsolation;private Boolean testWhileIdle;private Boolean testOnBorrow;private Boolean testOnReturn;private String validationQuery;private Integer validationQueryTimeout;private Boolean useGlobalDataSourceStat;private Boolean asyncInit;private String filters;private Boolean clearFiltersEnable;private Boolean resetStatEnable;private Integer notFullTimeoutRetryCount;private Integer maxWaitThreadCount;private Boolean failFast;private Long phyTimeoutMillis;private Long phyMaxUseCount;private Boolean keepAlive;private Boolean poolPreparedStatements;private Boolean initVariants;private Boolean initGlobalVariants;private Boolean useUnfairLock;private Boolean killWhenSocketReadTimeout;private Properties connectionProperties;private Integer maxPoolPreparedStatementPerConnectionSize;private String initConnectionSqls;private Boolean sharePreparedStatements;private Integer connectionErrorRetryAttempts;private Boolean breakAfterAcquireFailure;private Boolean removeAbandoned;private Integer removeAbandonedTimeoutMillis;private Boolean logAbandoned;private Integer queryTimeout;private Integer transactionQueryTimeout;private String publicKey;private Integer connectTimeout;private Integer socketTimeout;private Long timeBetweenConnectErrorMillis;private Map<String, Object> wall = new HashMap<>();private Map<String, Object> slf4j = new HashMap<>();private Map<String, Object> log4j = new HashMap<>();private Map<String, Object> log4j2 = new HashMap<>();private Map<String, Object> commonsLog = new HashMap<>();private Map<String, Object> stat = new HashMap<>();private List<String> proxyFilters = new ArrayList<>();
}

3.示例项目

3.1. pom

3.1.1. 依赖版本定义

 <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><ds.version>4.1.2</ds.version><mybatis-spring-boot-starter.version>3.0.0</mybatis-spring-boot-starter.version><druid.version>1.2.18</druid.version><p6spy.version>3.9.1</p6spy.version><h2.version>2.2.220</h2.version><spring-boot-dependencies.version>2.7.13</spring-boot-dependencies.version>
</properties>

3.1.2. 依赖版本管理

<dependencyManagement><dependencies><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>${ds.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot-dependencies.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-ui</artifactId><version>1.7.0</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis-spring-boot-starter.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>${druid.version}</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.version}</version></dependency><dependency><groupId>com.h2database</groupId><artifactId>h2</artifactId><version>${h2.version}</version></dependency></dependencies></dependencyManagement>

3.1.3. pom依赖

 <dependencies><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.springdoc</groupId><artifactId>springdoc-openapi-ui</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>provided</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

3.2. 源代码

3.2.1. DruidApplication

import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@Slf4j
@SpringBootApplication
@MapperScan("com.icepip.samples.druid.mapper")
public class DruidApplication {public static void main(String[] args) {SpringApplication.run(DruidApplication.class, args);log.info("open http://localhost:8080/swagger-ui.html \n" +"http://localhost:8080/druid/index.html");}
}

3.2.2. UserService

import com.icepip.samples.druid.entity.User;import java.util.List;public interface UserService {List<User> selectMasterUsers();List<User> selectSlaveUsers();void addUser(User user);void deleteUserById(Long id);
}

3.2.2. UserServiceImpl

在切换数据源的时候使用注解 @DS("slave")

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.samples.druid.entity.User;
import com.baomidou.samples.druid.mapper.UserMapper;
import com.baomidou.samples.druid.service.UserService;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class UserServiceImpl implements UserService {private final UserMapper userMapper;public UserServiceImpl(UserMapper userMapper) {this.userMapper = userMapper;}@Overridepublic List<User> selectMasterUsers() {return userMapper.selectUsers(1);}@DS("slave")@Overridepublic List<User> selectSlaveUsers() {return userMapper.selectUsers(1);}@Overridepublic void addUser(User user) {userMapper.addUser(user.getName(), user.getAge());}@Overridepublic void deleteUserById(Long id) {userMapper.deleteUserById(id);}
}

3.2.3. UserMapper

import com.baomidou.icepip.druid.entity.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Component;import java.util.List;@Component
public interface UserMapper {@Select("select * from t_user where age > #{age}")List<User> selectUsers(@Param("age") Integer age);@SuppressWarnings("UnusedReturnValue")@Insert("insert into t_user (name,age) values (#{name},#{age})")boolean addUser(@Param("name") String name, @Param("age") Integer age);@Delete("delete from t_user where id = #{id}")void deleteUserById(Long id);
}

3.2.3. User

import lombok.Data;@Data
public class User {private Integer id;private String name;private Integer age;
}

3.2.4. UserDto

import lombok.Data;@Data
public class UserDto {private Integer id;private String name;private Integer age;
}

3.2.5. UserController

import com.baomidou.icepip.druid.entity.User;
import com.baomidou.icepip.druid.service.UserService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;import java.util.List;
import java.util.Random;@RestController
@AllArgsConstructor
@RequestMapping("/users")
public class UserController {private static final Random RANDOM = new Random();private final UserService userService;@GetMapping("master")public List<User> masterUsers() {return userService.selectMasterUsers();}@GetMapping("slave")public List<User> slaveUsers() {return userService.selectSlaveUsers();}@PostMappingpublic User addUser() {User user = new User();user.setName("测试用户" + RANDOM.nextInt());user.setAge(RANDOM.nextInt(100));userService.addUser(user);return user;}@DeleteMapping("{id}")public String deleteUser(@PathVariable Long id) {userService.deleteUserById(id);return "成功删除用户" + id;}
}

3.2.6. 示例sql

CREATE TABLE IF NOT EXISTS t_user
(id   BIGINT(20)  NOT NULL AUTO_INCREMENT,`name` VARCHAR(30) NULL DEFAULT NULL,age  INT(11)     NULL DEFAULT NULL,PRIMARY KEY (id)
);

4.参考文档

1.多数据源 https://baomidou.com/pages/a61e1b/#dynamic-datasource

相关文章:

Spring Boot 配置多数据源【最简单的方式】

Druid连接池 Spring Boot 配置多数据源【最简单的方式】 文章目录 Druid连接池 Spring Boot 配置多数据源【最简单的方式】 0.前言1.基础介绍2.步骤2.1. 引入依赖2.2. 配置文件2.3. 核心源码Druid数据源创建器Druid配置项 DruidConfig 3.示例项目3.1. pom3.1.1. 依赖版本定义3.…...

1、Java简介+DOS命令+编译运行+一个简单的Java程序

Java类型&#xff1a; JavaSE 标准版&#xff1a;以前称为J2SE JavaEE 企业版&#xff1a;包括技术有&#xff1a;Servlet、Jsp&#xff0c;以前称为J2EE JavaME 微型版&#xff1a;以前称为J2ME Java应用&#xff1a; Android平台应用。 大数据平台开发&#xff1a;Hadoo…...

Linux 文件与目录管理,Linux 文件内容查看

目录 Linux 文件与目录管理 处理目录的常用命令 ls (列出目录) mv (移动文件与目录,或修改名称)...

Mysql按小时进行分组统计数据

目录 前言 按1小时分组统计 按2小时分组统计 按X小时分组统计 前言 统计数据时这种是最常见的需求场景&#xff0c;今天写需求时发现按2小时进行分组统计也特别简单&#xff0c;特此记录下。 按1小时分组统计 sql&#xff1a; select hour(pass_time) …...

springboot3日志配置

简介 Spring 使用commons-logging作为内部日志&#xff0c;但是底层日志实现是开放的&#xff0c;可以对接其他日志框架 spring5以及以后common-logging被spring直接自己写了 支持jul, log4j2,logback&#xff0c;springBoot提供了默认的控制台输出配置&#xff0c;也可以配置…...

7款轻量级平面图设计软件推荐

平面图设计的痕迹体现在日常生活的方方面面&#xff0c;如路边传单、杂志、产品包装袋或手机开屏海报等&#xff0c;平面设计软件层出不穷。Photoshop是大多数平面图设计初学者的入门软件&#xff0c;但随着设计师需求的不断提高&#xff0c;平面图设计软件Photoshop逐渐显示出…...

SpringCloud实用篇5——elasticsearch基础

目录 1.初识elasticsearch1.1 了解ES1.1.1 elasticsearch的作用1.1.2 ELK技术栈1.1.3 elasticsearch和lucene1.1.4 总结 1.2.倒排索引1.2.1.正向索引1.2.2.倒排索引1.2.3.正向和倒排 1.3 es的一些概念1.3.1 文档和字段1.3.2 索引和映射1.3.3 mysql与elasticsearch 1.4 部署单点…...

SpringCloud整体架构概览

什么是SpringCloud 目标 协调任何服务&#xff0c;简化分布式系统开发。 简介 构建分布式系统不应该是复杂的&#xff0c;SpringCloud对常见的分布式系统模式提供了简单易用的编程模型&#xff0c;帮助开发者构建弹性、可靠、协调的应用程序。SpringCloud是在SpringBoot的基…...

(el-switch)操作(不使用 ts):Element-plus 中 Switch 将默认值修改为 “true“ 与 “false“(字符串)来控制开关

Ⅰ、Element-plus 提供的 Switch 开关组件与想要目标情况的对比&#xff1a; 1、Element-plus 提供 Switch 组件情况&#xff1a; 其一、Element-ui 自提供的 Switch 代码情况为(示例的代码)&#xff1a; // Element-plus 自提供的代码&#xff1a; // 此时是使用了 ts 语言环…...

AI绘画网站都有哪些比较好用?

人工智能绘画网站是一种利用人工智能技术进行图像处理和创作的网站。这些绘画网站通常可以帮助艺术家以人工智能绘画的形式快速生成有趣、美丽和独特的绘画作品。无论你是专业的艺术家还是对人工智能绘画感兴趣的普通人&#xff0c;人工智能绘画网站都可以为你提供新的创作灵感…...

Android应用开发(35)SufaceView基本用法

Android应用开发学习笔记——目录索引 参考Android官网&#xff1a;https://developer.android.com/reference/android/view/SurfaceView 一、SurfaceView简介 SurfaceView派生自View&#xff0c;提供嵌入视图层次结构内部的专用绘图表面&#xff0c;SurfaceView可以在主线程之…...

原生JS手写扫雷小游戏

场景 实现一个完整的扫雷游戏需要一些复杂的逻辑和界面交互。我将为你提供一个简化版的扫雷游戏示例&#xff0c;帮助你入门。请注意&#xff0c;这只是一个基本示例&#xff0c;你可以根据自己的需求进行扩展和改进。 思路 创建游戏板&#xff08;Grid&#xff09;&#xff1…...

网络安全进阶学习第十五课——Oracle SQL注入

文章目录 一、Oracle数据库介绍二、Oracle和MySQL的语法差异&#xff1a;三、Oracle的数据库结构四、Oracle的重点系统表五、Oracle权限分类1、系统权限2、实体权限3、管理角色 六、oracle常用信息查询方法七、联合查询注入1、order by 猜字段数量2、查数据库版本和用户名3、查…...

线程池死循环系统卡住

案例&#xff1a; 同一个线程池。 首先核心线程数是8&#xff0c;我一次提交了 > 8个主任务&#xff0c;然后主任务又各自开启了几个子任务。 所以子任务没有核心线程来跑&#xff0c;只能放进阻塞队列等。 但主任务又等待子任务的结果&#xff0c;不释放占用线程&#xff…...

多用户微商城多端智慧生态电商系统搭建

多用户微商城多端智慧生态电商系统的搭建步骤如下&#xff1a; 系统规划&#xff1a;在搭建多用户微商城多端智慧生态电商系统之前&#xff0c;需要进行系统规划。包括确定系统的目标、功能、架构、技术选型、开发流程等方面。市场调研&#xff1a;进行市场调研&#xff0c;了…...

基于Kubeadm部署k8s集群:下篇

继续上篇内容 目录 7、安装flannel 8、节点管理命令 三、安装Dashboard UI 1、部署Dashboard 2、开放端口设置 3、权限配置 7、安装flannel Master 节点NotReady 的原因就是因为没有使用任何的网络插件&#xff0c;此时Node 和Master的连接还不正常。目前最流行的Kuber…...

【Python matplotlib】鼠标右键移动画布

在 Matplotlib 中&#xff0c;鼠标右键移动画布的功能通常是通过设置交互模式来实现的&#xff0c;例如使用 mpl_connect 方法。以下是一个示例代码&#xff0c;展示如何在 Matplotlib 中使用 mpl_connect 方法来实现鼠标右键移动画布的功能&#xff1a; import numpy as np …...

Sleuth+Zipkin服务链路追踪

微服务架构是一个分布式架构&#xff0c;它按业务划分服务单元。一个分布式系统往往有很多个服务单元。由于服务单元数量众多&#xff0c;业务的复杂性&#xff0c;如果出现了错误和异常&#xff0c;很难去定位。主要体现在&#xff0c;一个请求可能需要调用很多个服务&#xf…...

100G光模块的应用案例分析:电信、云计算和大数据领域

100G光模块是一种高速光模块&#xff0c;由于其高速率和低延迟的特性&#xff0c;在电信、云计算和大数据领域得到了广泛的应用。在本文中&#xff0c;我们将深入探讨100G光模块在这三个领域的应用案例。 一、电信领域 在电信领域&#xff0c;100G光模块被广泛用于构建高速通…...

MongoDB安装和配置

一、MongoDB安装和配置 1、进入官网下载你所需要的安装版本&#xff0c;点击直通官网 Step1&#xff1a;进入官网后&#xff0c;将看到如下界面&#xff0c;点击上方导航栏Products&#xff0c;找到Community Server Step2&#xff1a;选择自己需要的版本、系统和压缩方式 2、下…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验

系列回顾&#xff1a; 在上一篇中&#xff0c;我们成功地为应用集成了数据库&#xff0c;并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了&#xff01;但是&#xff0c;如果你仔细审视那些 API&#xff0c;会发现它们还很“粗糙”&#xff1a;有…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...