SpringBoot教程(二十五) | SpringBoot配置多个数据源

SpringBoot教程(二十五) | SpringBoot配置多个数据源

  • 前言
  • 方式一:使用dynamic-datasource-spring-boot-starter
    • 引入maven依赖
    • 配置数据源
    • 动态切换数据源实战
  • 方式二:使用AbstractRoutingDataSource
    • 1. 创建数据源枚举类
    • 2. 创建数据源上下文持有者
    • 3. 创建自定义的 AbstractRoutingDataSource
    • 4. 配置yml文件
    • 5. 配置数据源
      • HikariCP 版本
      • Druid 版本
    • 6. 自定义多数据源切换注解
    • 7. 使用 AOP 或拦截器设置数据源键
    • 8. 在服务层 测试使用
    • 总结
  • 方式三:分包方式
    • 1. 添加依赖
    • 2. application.yml 配置文件
    • 3. DataSourceConfig1.java 配置类
    • 4. DataSourceConfig2.java 配置类
    • 5. Mapper接口和XML文件
    • 6. 使用Mapper接口的服务类
    • 总结

前言

SpringBoot配置多数据源指的是在一个Spring Boot项目中配置和连接到多个数据库实例的能力。
这种架构允许应用程序根据不同的业务需求、数据类型或性能要求,与多个独立的数据库环境交互。
在实现上,每个数据源都有自己的连接池、事务管理和数据访问对象。

方式一:使用dynamic-datasource-spring-boot-starter

引入maven依赖

Spring Boot 3 区别其他版本,使用的是dynamic-datasource-spring-boot3-starter ,
其他版本的 Spring Boot 使用 dynamic-datasource-spring-boot-starter , 除了依赖区别,其他配置和使用方式新老版本无差别。

Spring Boot 3

<dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot3-starter</artifactId><version>4.2.0</version>
</dependency>

Spring 1.5.x 及 Spring 2.x.x

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

配置数据源

spring:datasource:dynamic:primary: master #设置默认的数据源或者数据源组,默认值即为 masterstrict: false # 设置严格模式,当数据源找不到时,是否抛出异常,默认为false不抛出datasource:master: # 主库type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driver # 3.2.0开始支持SPI可省略此配置url: jdbc:mysql://www.youlai.tech:3306/youlai_boot?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=trueusername: youlaipassword: 123456slave: # 从库type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/youlai_boot?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=trueusername: rootpassword: 123456

动态切换数据源实战

注解切换数据源
@DS注解是 dynamic-datasource-spring-boot-starter提供的
@DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。

注解结果
没有@DS默认数据源
@DS(“dsName”)dsName可以为组名也可以为具体某个库的名称
/*** 主库查询*/
@DS("master")
@Select("select * from sys_user where id = #{userId}")
SysUser getUserFromMaster(Long userId);/*** 从库查询*/
@DS("slave")
@Select("select * from sys_user where id = #{userId}")
SysUser getUserFromSlave(Long userId);

单元测试类

package com.youlai.system.mapper;import com.youlai.system.model.entity.SysUser;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest
@Slf4j
class SysUserMapperTest {@Autowiredprivate SysUserMapper userMapper;private final Long userId = 1L;/*** 测试注解方式切换数据源*/@Testvoid testSwitchDataSourceByAnnotation() {SysUser masterUser = userMapper.getUserFromMaster(userId);log.info("用户ID:{} 主库姓名:{}", userId, masterUser.getNickname());SysUser slaveUser = userMapper.getUserFromSlave(userId);log.info("用户ID:{} 从库姓名:{}", userId, slaveUser.getNickname());}
}

测试结果

在这里插入图片描述

方式二:使用AbstractRoutingDataSource

AbstractRoutingDataSource 是 Spring 框架中用于实现多数据源路由的一个抽象类。
它允许你在运行时根据某种键(通常是线程本地变量)动态地选择数据源。

1. 创建数据源枚举类

/*** 数据源*/
public enum DataSourceType {/*** 数据源1* */DB1,/*** 数据源2* */DB2
}

2. 创建数据源上下文持有者

首先,你需要一个类来持有当前线程的数据源键(DataSource Type)。这通常是通过 ThreadLocal 实现的。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** 数据源切换处理*/
public class DynamicDataSourceContextHolder {public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);/*** 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,* 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。*/private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();/*** 设置数据源的变量*/public static void setDataSourceType(String dsType) {log.info("切换到{}数据源", dsType);CONTEXT_HOLDER.set(dsType);}/*** 获得数据源的变量*/public static String getDataSourceType() {return CONTEXT_HOLDER.get();}/*** 清空数据源变量*/public static void clearDataSourceType() {CONTEXT_HOLDER.remove();}
}

3. 创建自定义的 AbstractRoutingDataSource

接下来,你需要扩展 AbstractRoutingDataSource 并重写 determineCurrentLookupKey 方法来返回当前线程的数据源键。

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** Spring的AbstractRoutingDataSource抽象类,实现动态数据源(他的作用就是动态切换数据源)* AbstractRoutingDataSource中的抽象方法determineCurrentLookupKey是实现数据源的route的核心,* 这里对该方法进行Override。【上下文DynamicDataSourceContextHolder为一线程安全的ThreadLocal】*/
public class DynamicDataSource extends AbstractRoutingDataSource {/*** 取得当前使用哪个数据源* @return dbTypeEnum*/@Overrideprotected Object determineCurrentLookupKey() {return DynamicDataSourceContextHolder.getDataSourceType();}
}

4. 配置yml文件

spring:datasource:# 配置第一个数据源db1:url: jdbc:mysql://localhost:3306/db1username: user1password: pass1driver-class-name: com.mysql.cj.jdbc.Driver# 配置第二个数据源db2:url: jdbc:mysql://localhost:3306/db2username: user2password: pass2driver-class-name: com.mysql.cj.jdbc.Driver

5. 配置数据源

在你的配置类中,你需要配置多个数据源,并将它们添加到 multipleDataSource 中。

HikariCP 版本

import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import com.example.springbootfull.quartztest.datasource.DynamicDataSource;
import com.example.springbootfull.quartztest.enums.DataSourceType;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.quartz.QuartzDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;/*** 多数据源配置*/
@Configuration
public class DataSourceConfig {/*** 创建第一个数据源** @return dataSource*/@Bean(name = "dataSource1")@ConfigurationProperties(prefix = "spring.datasource.db1")public DataSource dataSource1() {return DataSourceBuilder.create().build();}/*** 创建第二个数据源** @return dataSource*/@Bean(name = "dataSource2")@ConfigurationProperties(prefix = "spring.datasource.db2")public DataSource dataSource2() {return DataSourceBuilder.create().build();}/*** 动态数据源配置* 多个相同类型的 Bean,那么就会出现歧义,需要使用@Qualifier* @Qualifier 是按名称来查找和注入 Bean 的* @return dataSource*/@Primary@Bean("multipleDataSource")public DataSource multipleDataSource(@Qualifier("dataSource1") DataSource db1,@Qualifier("dataSource2") DataSource db2) {DynamicDataSource dynamicDataSource = new DynamicDataSource();Map<Object, Object> dataSources = new HashMap<>();dataSources.put(DataSourceType.DB1, db1);dataSources.put(DataSourceType.DB2, db2);dynamicDataSource.setTargetDataSources(dataSources);//默认数据源dynamicDataSource.setDefaultTargetDataSource(db1);return dynamicDataSource;}@Bean("sqlSessionFactory")public SqlSessionFactory sqlSessionFactory(@Qualifier("multipleDataSource") DataSource multipleDataSource) throws Exception {// 导入mybatissqlsession配置MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();// 指明数据源sessionFactory.setDataSource(multipleDataSource);// 设置mapper.xml的位置路径Resource[] resources = new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/**/*.xml");sessionFactory.setMapperLocations(resources);//指明实体扫描(多个package用逗号或者分号分隔)//sessionFactory.setTypeAliasesPackage("com.szylt.projects.project.entity");// 导入mybatis配置MybatisConfiguration configuration = new MybatisConfiguration();configuration.setJdbcTypeForNull(JdbcType.NULL);configuration.setMapUnderscoreToCamelCase(true);configuration.setCacheEnabled(false);sessionFactory.setConfiguration(configuration);return sessionFactory.getObject();}//数据源事务配置@Beanpublic PlatformTransactionManager transactionManager(DataSource multipleDataSource) {return new DataSourceTransactionManager(multipleDataSource);}}

Druid 版本

需要先引入 Druid 依赖,这里使用的是 Druid 官方的 Starter

<dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.8</version>
</dependency>

然后,在properties配置文件中 为每个数据源配置DruidDataSour数据库连接池

spring.datasource.db1.type=com.alibaba.druid.pool.DruidDataSour
spring.datasource.db2.type=com.alibaba.druid.pool.DruidDataSour

接着把一下DataSourceConfig 类里面的 按下面的操作,就好了

  • DataSource 对象 换成 DruidDataSource 对象
  • DataSourceBuilder 对象 换成 DruidDataSourceBuilder 对象

6. 自定义多数据源切换注解

import com.example.springbootfull.quartztest.enums.DataSourceType;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** 自定义多数据源切换注解* 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准*/
@Target({ ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource
{/*** 切换数据源名称* 默认为DB1*/public DataSourceType value() default DataSourceType.DB1;
}

7. 使用 AOP 或拦截器设置数据源键

为了在使用时能够动态地切换数据源,你需要在执行数据库操作之前设置数据源键。
这通常是通过 AOP(面向切面编程)或拦截器来实现的。

需要引入aop依赖

<!--spring切面aop依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId>
</dependency>

以下是一个使用 AOP 的示例:

以下这个位置,记得 替换成你项目中 自定义注解 DataSource 所在的具体位置
@Pointcut(“@annotation(com.example.xx.xx.DataSource) || @within(com.example.xx.xx.DataSource)”)

import java.util.Objects;import com.example.springbootfull.quartztest.annotation.DataSource;
import com.example.springbootfull.quartztest.datasource.DynamicDataSourceContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;/*** 多数据源处理**/
@Aspect
@Order(1)
@Component
public class DataSourceAspect {protected Logger logger = LoggerFactory.getLogger(getClass());//此处替换成你项目中 自定义注解 DataSource 所在的具体位置@Pointcut("@annotation(com.example.xx.xx.DataSource)"+ "|| @within(com.example.xx.xx.DataSource)")public void dsPointCut() {}@Around("dsPointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {DataSource dataSource = getDataSource(point);if (dataSource != null) {DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());}try {return point.proceed();} finally {// 销毁数据源 在执行方法之后DynamicDataSourceContextHolder.clearDataSourceType();}}/*** 获取需要切换的数据源*/public DataSource getDataSource(ProceedingJoinPoint point) {MethodSignature signature = (MethodSignature) point.getSignature();DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);if (Objects.nonNull(dataSource)) {return dataSource;}return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);}
}

8. 在服务层 测试使用

最后,在你的服务层方法上使用 @DataSource 注解来指定要使用的数据源。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class MyService {@Autowiredprivate MyMapper myMapper; // 假设MyMapper是一个Mapper接口// 使用第一个数据源@DataSource(value = DataSourceType.DB1)@Transactionalpublic void useDb1() {// 执行数据库操作myMapper.someMethod();}// 使用第二个数据源@DataSource(value = DataSourceType.DB2)@Transactionalpublic void useDb2() {// 执行数据库操作myMapper.anotherMethod();}
}

总结

通过上述步骤,你已经成功地在 Spring Boot 项目中配置了基于 AbstractRoutingDataSource 的多数据源支持。
当你调用服务层的方法时,AOP 拦截器会根据 @DataSource 注解的值设置当前线程的数据源键,从而动态地选择数据源。

方式三:分包方式

  1. 配置多个数据源:在Spring Boot的配置文件中(如application.propertiesapplication.yml),配置多个数据源的信息,包括URL、用户名、密码等。
  2. 创建数据源配置类:为每个数据源创建一个配置类,使用@Configuration注解标注,并在类中定义数据源(DataSource)、事务管理器(TransactionManager)以及SqlSessionFactory等Bean。
  3. 指定Mapper扫描路径:使用@MapperScan注解指定每个数据源对应的Mapper扫描路径,以便Spring Boot能够正确地加载和注册Mapper接口。

1. 添加依赖

首先,在pom.xml文件中添加必要的依赖,包括Spring Boot的Web启动器、MyBatis的Spring Boot启动器、数据库驱动等。例如:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>版本号</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- 其他依赖 -->
</dependencies>

2. application.yml 配置文件

# Spring Boot应用程序的配置文件
spring:datasource:# 第一个数据源的配置db1:jdbc-url: jdbc:mysql://localhost:3306/test1?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=GMT%2B8# 数据库用户名username: root# 数据库密码password: 123456# 数据库驱动类名driver-class-name: com.mysql.cj.jdbc.Driver# 第二个数据源的配置db2:jdbc-url: jdbc:mysql://localhost:3306/test2?characterEncoding=utf8&useUnicode=true&useSSL=false&serverTimezone=GMT%2B8username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driver

3. DataSourceConfig1.java 配置类

// 使用@Configuration注解表明这是一个配置类
@Configuration
// 使用@MapperScan注解指定Mapper接口所在的包,并指定SqlSessionFactory的引用
@MapperScan(basePackages = "com.example.mapper.db1", sqlSessionFactoryRef = "db1SqlSessionFactory")
public class DataSourceConfig1 {// 使用@Primary注解表明这是默认的数据源(如果有多个数据源时)// 使用@Bean注解表明这是一个Spring管理的bean,name属性指定bean的名称// 使用@ConfigurationProperties注解读取application.yml中的配置@Primary@Bean(name = "db1DataSource")@ConfigurationProperties(prefix = "spring.datasource.db1")public DataSource getDb1DataSource() {// 创建并返回数据源对象return DataSourceBuilder.create().build();}// 创建一个SqlSessionFactory对象,用于MyBatis的SQL会话管理@Primary@Bean(name = "db1SqlSessionFactory")public SqlSessionFactory db1SqlSessionFactory(@Qualifier("db1DataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();// 设置数据源sessionFactoryBean.setDataSource(dataSource);// 设置Mapper XML文件的位置sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/db1/*.xml"));// 返回SqlSessionFactory对象return sessionFactoryBean.getObject();}
}

4. DataSourceConfig2.java 配置类

这个类与DataSourceConfig1.java类似,但它是为第二个数据源配置的。

// 使用@Configuration注解表明这是一个配置类
@Configuration
// 使用@MapperScan注解指定第二个数据源对应的Mapper接口所在的包
@MapperScan(basePackages = "com.example.mapper.db2", sqlSessionFactoryRef = "db2SqlSessionFactory")
public class DataSourceConfig2 {// 创建一个名为db2DataSource的数据源bean@Bean(name = "db2DataSource")@ConfigurationProperties(prefix = "spring.datasource.db2")public DataSource getDb2DataSource() {// 创建并返回数据源对象return DataSourceBuilder.create().build();}// 创建一个名为db2SqlSessionFactory的SqlSessionFactory对象@Bean(name = "db2SqlSessionFactory")public SqlSessionFactory db2SqlSessionFactory(@Qualifier("db2DataSource") DataSource dataSource) throws Exception {SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();// 设置数据源sessionFactoryBean.setDataSource(dataSource);// 设置第二个数据源对应的Mapper XML文件的位置sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mapper/db2/*.xml"));// 返回SqlSessionFactory对象return sessionFactoryBean.getObject();}
}

5. Mapper接口和XML文件

com.example.mapper.db1com.example.mapper.db2包下分别创建Mapper接口,这些接口定义了操作数据库的方法。
同时,在resources/mapper/db1resources/mapper/db2目录下创建对应的XML文件,这些文件包含了SQL语句和映射规则。

6. 使用Mapper接口的服务类

// 使用@Service注解表明这是一个服务类
@Service
public class MyService {// 注入第一个数据源的Mapper接口@Autowiredprivate Db1Mapper db1Mapper;// 注入第二个数据源的Mapper接口@Autowiredprivate Db2Mapper db2Mapper;// 使用第一个数据源的方法public void useDb1() {// 调用db1Mapper的方法执行数据库操作}// 使用第二个数据源的方法public void useDb2() {// 调用db2Mapper的方法执行数据库操作}
}

总结

通过上述配置,您可以在Spring Boot项目中配置多个数据源,并通过不同的Mapper接口来操作这些数据源。
每个数据源都有自己的配置类、数据源对象、SqlSessionFactory对象和Mapper接口。
这样,您就可以在同一个项目中方便地访问多个数据库了。

参考文章
【1】Spring Boot 3 整合 Mybatis-Plus 动态数据源实现多数据源切换

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/60903.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ZooKeeper单机、集群模式搭建教程

单点配置 ZooKeeper在启动的时候&#xff0c;默认会读取/conf/zoo.cfg配置文件&#xff0c;该文件缺失会报错。因此&#xff0c;我们需要在将容器/conf/挂载出来&#xff0c;在制定的目录下&#xff0c;添加zoo.cfg文件。 zoo.cfg logback.xml 配置文件的信息可以从二进制包…

【大数据学习 | HBASE高级】hbase-phoenix 与二次索引应用

1. hbase-phoenix的应用 1.1 概述&#xff1a; 上面我们学会了hbase的操作和原理&#xff0c;以及外部集成的mr的计算方式&#xff0c;但是我们在使用hbase的时候&#xff0c;有的时候我们要直接操作hbase做部分数据的查询和插入&#xff0c;这种原生的方式操作在工作过程中还…

拆解测试显示Mac Mini (2024)固态硬盘并未锁定 互换硬盘后仍可使用

此前已经有维修达人尝试将 Mac Mini (2024) 固态硬盘上的 NAND 闪存拆下并替换实现扩容&#xff0c;例如可以从 256GB 扩容到 2TB。虽然接口类似于 NVMe M.2 SSD 但直接安装普通硬盘是无效的&#xff0c;苹果仍然通过某种机制检测硬盘是否能够兼容。 不过知名拆解网站 iFixit 的…

主界面获取个人信息客户端方

主界面获取个人信息客户端方 前言 上一集我们完成了websocket身份验证的内容&#xff0c;那么这一集开始我们将要配合MockServer来完成主界面获取个人信息的内容。 需求分析 我们这边是完成客户端那方的内容&#xff0c;当客户端登录成功之后&#xff0c;我们就要从服务器获…

Spring整合Redis

前言 在Spring项目中整合Redis&#xff0c;能显著提升数据缓存、分布式锁、会话管理等操作的效率。Jedis作为轻量级的Java Redis客户端&#xff0c;搭配Spring Data Redis模块&#xff0c;能够简化Redis的连接和数据操作&#xff0c;实现更高性能的读写与灵活的缓存管理。本文…

爬虫——Requests库的使用

在爬虫开发中&#xff0c;HTTP请求是与服务器进行交互的关键操作。通过发送HTTP请求&#xff0c;爬虫可以获取目标网页或接口的数据&#xff0c;而有效地处理请求和响应是爬虫能够高效且稳定运行的基础。Requests库作为Python中最常用的HTTP请求库&#xff0c;因其简洁、易用和…

LinkedHashMap实现LRU

LRU 环境&#xff1a;JDK11 最近接触LRU(Least Recently Used)&#xff0c;即最近最少使用&#xff0c;也称淘汰算法&#xff0c;在JDK中LinkedHashMap有相关实现 LRU的LinkedHashMap实现 LinkedHashMap继承HashMap。所以内存的存储结构和HashMap一样&#xff0c;但是LinkedH…

IDEA部署AI代写插件

前言 Hello大家好&#xff0c;当下是AI盛行的时代&#xff0c;好多好多东西在AI大模型的趋势下都变得非常的简单。 比如之前想画一幅风景画得先去采风&#xff0c;然后写实什么的&#xff0c;现在你只需描述出你想要的效果AI就能够根据你的描述在几分钟之内画出一幅你想要的风景…

27-压力测试

测试目标 & 测试数据 ● 测试目标 ○ 测试集群的读写性能 / 做集群容量规划 ○ 对 ES 配置参数进行修改&#xff0c;评估优化效果 ○ 修改 Mapping 和 Setting&#xff0c;对数据建模进行优化&#xff0c;并测试评估性能改进 ○ 测试 ES 新版本&#xff0c;结合实际场…

4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明

4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明 文章目录 4. Spring Cloud Ribbon 实现“负载均衡”的详细配置说明前言1. Ribbon 介绍1.1 LB(Load Balance 负载均衡) 2. Ribbon 原理2.2 Ribbon 机制 3. Spring Cloud Ribbon 实现负载均衡算法-应用实例4. 总结&#x…

vue3【实战】切换全屏【组件封装】FullScreen.vue

效果预览 原理解析 使用 vueUse 里的 useFullscreen() 实现 代码实现 技术方案 vue3 vite UnoCSS vueUse 组件封装 src/components/FullScreen.vue <template><component:is"tag"click"toggle":class"[!isFullscreen ? i-ep:full-sc…

docker:基于Dockerfile镜像制作完整案例

目录 摘要目录结构介绍起始目录package目录target目录sh目录init.sh脚本start.sh脚本stop.sh脚本restart.sh脚本 config目录 步骤1、编写dockerfilescript.sh脚本 2、构件镜像查看镜像 3、保存镜像到本地服务器4、复制镜像文件到指定目录&#xff0c;并执行init.sh脚本5、查看挂…

微澜:用 OceanBase 搭建基于知识图谱的实时资讯流的应用实践

本文作者&#xff1a; 北京深鉴智源科技有限公司架构师 郑荣凯 本文整理自北京深鉴智源科技有限公司架构师郑荣凯&#xff0c;在《深入浅出 OceanBase 第四期》的分享。 知识图谱是一项综合性的系统工程&#xff0c;需要在在各种应用场景中向用户展示经过分页的一度关系。 微…

消息中间件分类

消息中间件&#xff08;Message Middleware&#xff09;是一种在分布式系统中实现跨平台、跨应用通信的软件架构。它基于消息传递机制&#xff0c;允许不同系统、不同编程语言的应用之间进行异步通信。 常见的消息中间件类型包括&#xff1a; 1. JMS&#xff08;Java Message S…

Mac上详细配置java开发环境和软件(更新中)

文章目录 概要JDK的配置JDK下载安装配置JDK环境变量文件 Idea的安装Mysql安装和配置Navicat Premium16.1安装安装Vscode安装和配置Maven配置本地仓库配置阿里云私服Idea集成Maven 概要 这里使用的是M3型片 14.6版本的Mac 用到的资源放在网盘 链接: https://pan.baidu.com/s/17…

[⑧5G NR]: PBCH payload生成

本篇博客记录下5G PBCH信道中payload数据的生成方式。PBCH payload一共32个比特&#xff0c;基本结构如下图&#xff1a; 根据SSB PDU中bchPayloadFlag的值有三种方式得到PBCH payload。 bchPayloadFlag 0&#xff1a;全部32比特由MAC层提供。 bchPayloadFlag 1&#xff1a;M…

预处理(1)(手绘)

大家好&#xff0c;今天给大家分享一下编译器预处理阶段&#xff0c;那么我们来看看。 上面是一些预处理阶段的知识&#xff0c;那么明天给大家讲讲宏吧。 今天分享就到这里&#xff0c;谢谢大家&#xff01;&#xff01;

EEG+EMG学习系列 (2) :实时 EEG-EMG 人机界面的下肢外骨骼控制系统

[TOC]( EEGEMG学习系列(2):实时 EEG-EMG 人机界面的下肢外骨骼控制系统) 论文地址&#xff1a;https://ieeexplore.ieee.org/abstract/document/9084126 论文题目&#xff1a;Real-Time EEG–EMG Human–Machine Interface-Based Control System for a Lower-Limb Exoskeleton …

用指针遍历数组

#include<stdio.h> int main() {//定义一个二维数组int arr[3][4] {{1,2,3,4},{2,3,4,5},{3,4,5,6},};//获取二维数组的指针int (*p)[4] arr;//二维数组里存的是一维数组int[4]for (int i 0; i < 3; i){//遍历一维数组for (int j 0; j <4; j){printf("%d &…

动态规划子数组系列(二) 环形子数组的最大和

题目&#xff1a; 解析&#xff1a; 代码&#xff1a; public int maxSubarraySumCircular(int[] nums) {int sum 0;int n nums.length;int[] f new int[n1];int[] g new int[n1];int ret 0, fmax -0x3f3f3f3f, gmin Integer.MAX_VALUE;for(int i 1; i < n; i)…