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 #设置默认的数据源或者数据源组,默认值即为 master
      strict: false # 设置严格模式,当数据源找不到时,是否抛出异常,默认为false不抛出
      datasource:
        master: # 主库
          type: com.alibaba.druid.pool.DruidDataSource
          driver-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=true
          username: youlai
          password: 123456
        slave: # 从库
          type: com.alibaba.druid.pool.DruidDataSource
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/youlai_boot?zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true
          username: root
          password: 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 {

    @Autowired
    private SysUserMapper userMapper;

    private final Long userId = 1L;

    /**
     * 测试注解方式切换数据源
     */
    @Test
    void 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
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}

4. 配置yml文件

spring:
  datasource:
    # 配置第一个数据源
    db1:
      url: jdbc:mysql://localhost:3306/db1
      username: user1
      password: pass1
      driver-class-name: com.mysql.cj.jdbc.Driver
    
    # 配置第二个数据源
    db2:
      url: jdbc:mysql://localhost:3306/db2
      username: user2
      password: pass2
      driver-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();
    }


    //数据源事务配置
    @Bean
    public 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 {

    @Autowired
    private MyMapper myMapper; // 假设MyMapper是一个Mapper接口

    // 使用第一个数据源
    @DataSource(value = DataSourceType.DB1)
    @Transactional
    public void useDb1() {
        // 执行数据库操作
        myMapper.someMethod();
    }

    // 使用第二个数据源
    @DataSource(value = DataSourceType.DB2)
    @Transactional
    public 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%2B8
      username: root
      password: 123456
      driver-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接口
    @Autowired
    private Db1Mapper db1Mapper;

    // 注入第二个数据源的Mapper接口
    @Autowired
    private Db2Mapper db2Mapper;

    // 使用第一个数据源的方法
    public void useDb1() {
        // 调用db1Mapper的方法执行数据库操作
    }

    // 使用第二个数据源的方法
    public void useDb2() {
        // 调用db2Mapper的方法执行数据库操作
    }
}

总结

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python 正则表达式进阶用法:分组与引用详解

Python 正则表达式进阶用法&#xff1a;分组与引用详解 正则表达式是一种用于字符串匹配和处理的强大工具。它不仅能识别简单的文本模式&#xff0c;还能通过更高级的特性来完成复杂的文本处理任务。本文将深入探讨 Python 正则表达式中的“分组”和“引用”——两个在高级匹配…

米家通过HomeAssistant控制笔记本电脑开关机

米家通过HomeAssistant控制笔记本电脑开关机 配置HomeAssistant配置EMQX mqtt自动化配置电脑关机实现电脑开机实现&#xff08;网络唤醒WOL包&#xff09; 环境准备&#xff1a; HomeAssistant&#xff1a;能配置接入米家的设备&#xff0c;我这里采用fnos安装MQTT服务器&…

前端环境配置

对于换公司的小伙伴来讲&#xff0c;重新安装环境&#xff0c;百度或许稍微有点麻烦&#xff0c;本文章让你无脑式直接操作&#xff0c;保证环境畅通无阻。 1.安装nvm-setup 该插件是一款管理nodeJs的包&#xff0c;无需你单独下载nodeJs去安装&#xff0c;只需要下载安装此…

[CKS] K8S AppArmor Set Up

最近准备花一周的时间准备CKS考试&#xff0c;在准备考试中发现有一个题目关于AppArmor Pod操作权限的问题。 ​ 专栏其他文章: [CKS] Create/Read/Mount a Secret in K8S-CSDN博客[CKS] Audit Log Policy-CSDN博客 -[CKS] 利用falco进行容器日志捕捉和安全监控-CSDN博客[CKS] …

提升自然排名的有效策略与方法

内容概要 在数字营销的快速发展背景下&#xff0c;自然排名的提升日益显得重要。自然排名不仅影响网站的流量&#xff0c;同时也直接关系到品牌的曝光度和市场竞争力。针对这个主题&#xff0c;我们将探讨多个关键因素&#xff0c;帮助读者更好地理解自然排名的重要性及其影响…

golang go语言 组建微服务架构详解 - 代码基于开源框架grpc+nacos服务管理配置平台

整体介绍&#xff1a; 本文主要介绍如何用go语言 来组建微服务的框架&#xff0c;grpc服务管理 示例框架 代码由grpcnacos go sdk 组成。 grpc负责将调用序列化并传递到远端&#xff0c;nacos负责服务发现和服务管理。 grpc和nacos都是开源产品。代码复制下来就能跑。 微服…

软件测试项目实战

软件测试是使用人工或者自动的手段来运行或者测定某个软件系统的过程&#xff0c;其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别。 在软件投入使用前&#xff0c;要经过一系列的严格测试&#xff0c;才能保证交付质量。 一、引言 1.编写目的 本文档…

基于百度飞桨paddle的paddlepaddle2.4.2等系列项目的运行

PPASR 必看&#xff01;&#xff01;&#xff01; PaddleSpeech develop --> PaddlePaddle 2.5.0/2.5.1 PaddleSpeech < 1.4.1 --> PaddlePaddle < 2.4.2 1.创建虚拟环境 conda create --name test python3.10 2.激活环境&#xff0c;安装ppasr的paddlepaddl…

MySQL数据库专栏(四)MySQL数据库链接操作C#篇

摘要 本篇文章主要介绍C#链接MySQL数据库的接口介绍&#xff0c;使用实例及注意事项&#xff0c;辅助类的封装及调用实例&#xff0c;可以直接移植到项目里面使用。 目录 1、添加引用 2、接口介绍 2.1、MySqlConnection 2.2、MySqlCommand 2.3、MySqlDataReader…

【Pikachu】File Inclusion文件包含实战

永远也不要忘记能够笑的坚强&#xff0c;就算受伤&#xff0c;我也从不彷徨。 1.File Inclusion(文件包含漏洞)概述 File Inclusion(文件包含漏洞)概述 文件包含&#xff0c;是一个功能。在各种开发语言中都提供了内置的文件包含函数&#xff0c;其可以使开发人员在一个代码…

计算机网络基本概念总结

IP地址 概念 使网络中的设备都有唯一的地址标识&#xff0c;用于表示其在网络中的位置。 格式 IP地址是一个32位的二进制数&#xff0c;通常被分割为4个8位二进制数&#xff08;也就是4个字节&#xff09;&#xff0c;如&#xff1a;01100100.00001000.00001010.00000110。通常…

CSS回顾-基础知识详解

一、引言 在前端开发领域&#xff0c;CSS 曾是构建网页视觉效果的关键&#xff0c;与 HTML、JavaScript 一起打造精彩的网络世界。但随着组件库的大量涌现&#xff0c;我们亲手书写 CSS 样式的情况越来越少&#xff0c;CSS 基础知识也逐渐被我们遗忘。 现在&#xff0c;这种遗…

RabbitMq项目实战--延迟队列实现超时订单处理

简单实现版 RabbitMq创建队列绑定交换机_rabbitmq 绑定交换机-CSDN博客 Configuration public class RabbitmqConfig {Value("${rabbitmq.exchange}")private String exchange;Value("${rabbitmq.host}")private String host;Value("${rabbitmq.por…

Vivado+Vscode联合打造verilog环境

一、Vivado下载安装 详细参考我另一篇文章&#xff1a; Vivado2022.2下载安装_fpga vivado下载-CSDN博客https://blog.csdn.net/weixin_61081689/article/details/143460790?spm1001.2014.3001.5501 二、Vscode下载安装 详细参考我另一篇文章&#xff1a; VscodeAnacond…

Unity 热更新 之 一篇文章完全入门AssetBundle

本篇知识来源于unity官方手册以及siki学院的相关教程,链接如下,仅作学习分享 AssetBundle&#xff08;创建打包&#xff09;入门学习(基于Unity2017) - SiKi学院|SiKi学堂 - unity|u3d|虚幻|ue4/5|java|python|人工智能|视频教程|在线课程 目录 0.热更新是什么 1.AssetBundl…

思考:linux Vi Vim 编辑器的简明原理,与快速用法之《 7 字真言 》@ “鱼爱返 说 温泉啊“ (**)

Linux vi/vim | 菜鸟教程 https://zhuanlan.zhihu.com/p/602675406 Linux Vim编辑器的基本使用_vim文本编辑器-CSDN博客 这里提出使用 vi / vim 进行简单的编辑操作的原因&#xff0c;主要是在容器镜像中&#xff0c;普遍都是使用这个。 在 linux 服务器应用场景&#x…

【网络安全 | 甲方建设】DDOS 防范教程

未经许可,不得转载。 文章目录 前言DDoSDDoS种类针对DDoS CC攻击的防护备份网站拦截HTTP请求带宽扩容使用CDN隐藏服务器真实IP关闭不必要的服务或端口限制SYN/ICMP流量启用反向代理前言 假设你是一个电商平台的管理员,网站每天都处理大量的用户请求,比如用户浏览商品、加入…

【WRF模拟】全过程总结:WPS预处理及WRF运行

【WRF模拟】全过程总结:WPS预处理及WRF运行 1 数据准备1.1 嵌套域设置(Customize domain)-基于QGis中gis4wrf插件1.2 静态地理数据1.2.1 叶面积指数LAI和植被覆盖度Fpar(月尺度)1.2.2 地面反照率(月尺度)1.2.3 土地利用类型+不透水面积1.2.4 数据处理:geotiff→tiff(W…

【青牛科技】 GC6153——TMI8152 的不二之选,可应用于摇头机等产品中

在电子工程领域&#xff0c;不断寻求性能更优、成本更低的解决方案是工程师们的永恒追求。今天&#xff0c;我们要为广大电子工程师带来一款极具竞争力的产品 —— GC6153&#xff0c;它将成为 TMI8152 的完美替代之选。 一、产品背景 随着科技的飞速发展&#xff0c;电子设备…

Openstack9--安装etcd分布式键-值对存储系统

只需在控制节点安装 yum -y install etcd 编辑配置文件 配图画线处需要更改&#xff0c;如果改行被#注释请删掉# 以取消注释 vi /etc/etcd/etcd.conf 修改的 ETCD_LISTEN_PEER_URLS"http://192.168.10.10:2380" ETCD_LISTEN_CLIENT_URLS"http://192.168.1…