springboot 2.4.4集成 hikari连接池多数据源实例

news2025/1/24 8:47:51

文章目录

  • 前言
  • 一、配置步骤
    • 1.1 pom配置
    • 1.2 application.properties配置
    • 1.3 DataSourceContextHolder类
    • 1.4 DynamicDataSource
    • 1.5 DataSourceconfig类配置
    • 1.6 配置TargetDataSource注解
    • 1.7 切面方法
    • 1.8 dao的写法
  • 二、测试验证
    • 2.1 启动springboot项目
    • 2.2 检查数据库连接
    • 2.3 debug看其他数据库属性是否生效
    • 2.4 看请求结果
  • 总结


前言

本文章展示如何使用hikari建立多数据源,发现网上的资料不全或者不对,这里展示如何
配置hikari多数据源附带连接池。


一、配置步骤

1.1 pom配置

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
         <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

这里仅需要这两个包即可,后面的springboot版本默认使用的hikari连接池不需要额外引入包。
在这里插入图片描述

1.2 application.properties配置

spring.datasource.test1.hikari.name=test1
spring.datasource.test1.hikari.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.test1.hikari.jdbcurl=jdbc:mysql://localhost:3306/test1?allowMultiQueries=true&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
spring.datasource.test1.hikari.username=root
spring.datasource.test1.hikari.password=123456


#客户端向池子请求连接的超时时间,超出则抛出一个SQLException。
#最小值:250毫秒。
#默认值:30000毫秒 单位ms
spring.datasource.test1.hikari.connection-timeout=30000
#控制池允许达到的最大大小,包括两者空闲和正在使用的连接
spring.datasource.test1.hikari.maximum-pool-size=2
#控制HikariCP试图维护的空闲连接的最小数量
spring.datasource.test1.hikari.minimum-idle=2
#控制连接在池中允许空闲的最长时间。单位ms
spring.datasource.test1.hikari.idle-timeout=600000
#控制连接池中连接的最长生命周期。使用中的连接永远不会被弃用,只有当它被关闭时才会被移除。针对每个连接,应用轻微的负面衰减,以避免连接池的大规模灭绝。
#我们强烈建议设置此值,应该比数据库或基础设施强制实施的连接时间限制短几秒钟。如果将其设置为0,则表示没有最大生命周期(无限生命周期),当然还要考虑idleTimeout设置。
#最小允许值为30000ms(30秒)。
#默认值为180000030分钟)
spring.datasource.test1.hikari.max-lifetime=1800000
#控制HikariCP尝试保持连接的频率 适用于空闲连接 5分钟检测一次
spring.datasource.test1.hikari.keep-aliveTime =300000
# 检测连接存活
spring.datasource.test1.hikari.connection-test-query=SELECT 1 FROM DUAL
spring.datasource.test1.hikari.pool-name =test1pool

spring.datasource.test2.hikari.name=test2
spring.datasource.test2.hikari.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.test2.hikari.jdbcurl=jdbc:mysql://localhost:3306/test2?allowMultiQueries=true&serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false
spring.datasource.test2.hikari.username=root
spring.datasource.test2.hikari.password=123456

#客户端向池子请求连接的超时时间,超出则抛出一个SQLException。
#最小值:250毫秒。
#默认值:30000毫秒 单位ms
spring.datasource.test2.hikari.connection-timeout=30000
#控制池允许达到的最大大小,包括两者空闲和正在使用的连接
spring.datasource.test2.hikari.maximum-pool-size=2
#控制HikariCP试图维护的空闲连接的最小数量
spring.datasource.test2.hikari.minimum-idle=2
#控制连接在池中允许空闲的最长时间。单位ms
spring.datasource.test2.hikari.idle-timeout=600000
#控制连接池中连接的最长生命周期。使用中的连接永远不会被弃用,只有当它被关闭时才会被移除。针对每个连接,应用轻微的负面衰减,以避免连接池的大规模灭绝。
#我们强烈建议设置此值,应该比数据库或基础设施强制实施的连接时间限制短几秒钟。如果将其设置为0,则表示没有最大生命周期(无限生命周期),当然还要考虑idleTimeout设置。
#最小允许值为30000ms(30秒)。
#默认值为180000030分钟)
spring.datasource.test2.hikari.max-lifetime=1800000
#控制HikariCP尝试保持连接的频率 适用于空闲连接 5分钟检测一次
spring.datasource.test2.hikari.keep-aliveTime =300000
# 检测连接存活
spring.datasource.test2.hikari.connection-test-query=SELECT 1 FROM DUAL
spring.datasource.test2.hikari.pool-name =test2pool

mybatis.mapperlocations=classpath:com/example/springdemo/demo/dao/*.xml

通用的配置如上面的,具体的含义如上面也做了解释,够一般互联网公司使用了,可以自己再微调参数,根据实际情况配置。

1.3 DataSourceContextHolder类

该类用来保存线程使用的数据源是哪一个。

package com.example.springdemo.demo.conifg.initDataSourceConfig;


/**
 * @author
 * @version 1.0
 * @className com.framework.web.config.initDataSourceConfig
 * @description 动态数据源上下文管理:设置数据源,获取数据源,清除数据源
 */
public class DataSourceContextHolder {
    // 存放当前线程使用的数据源类型
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<String>();

    /**
     * @param type 1 值
     * @titel 设置数据源
     * @description 设置数据源
     * @author
     */
    public static void setDataSource(String type) {
        CONTEXT_HOLDER.set(type);
    }

    /**
     * @return java.lang.String
     * @titel 获取数据源
     * @description 获取数据源
     * @author
     */
    public static String getDataSource() {
        return CONTEXT_HOLDER.get();
    }

    /**
     * @titel 清除数据源
     * @description 清除数据源
     * @author
     */
    public static void clearDataSource() {
        CONTEXT_HOLDER.remove();
    }

}

1.4 DynamicDataSource

获取当前数据源

package com.example.springdemo.demo.conifg.initDataSourceConfig;

import com.example.springdemo.demo.conifg.annotation.TargetDataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

/**
 * @author
 * @version 1.0
 * @className com.framework.web.config.initDataSourceConfig
 * @description 动态数据源,每执行一次数据库,动态获取数据源
 */
public class DynamicDataSource extends AbstractRoutingDataSource {
    /**
     * @return java.lang.Object 值
     * @titel 获取当前数据源
     * @description 获取当前数据源
     * @author
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSource();
    }
}

1.5 DataSourceconfig类配置

package com.example.springdemo.demo.conifg.initDataSourceConfig;

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
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.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author
 * @version 1.0
 * @className com.framework.web.config.initDataSourceConfig
 * @description 数据源初始化类
 * @datetime 2019/10/11
 */
@Configuration
//@EnableTransactionManagement
@MapperScan(value = "com.example.springdemo.demo.dao.**")
public class DataSourceConfig {
    //    扫描XML路径注入
    @Value("${mybatis.mapper-locations}")
    private String mapperLocations;


    @Bean(name = "test1Config")
    @ConfigurationProperties(prefix = "spring.datasource.test1.hikari")
    public HikariConfig test1Config(){
        return new HikariConfig();
    }
    
    /**
     * @return javax.sql.DataSource 返回数据源
     * @title 只读数据源
     * @description 只读数据源
     * @author
     * @datetime 2019/12/27 17:25
     */
    @Bean(name = "test1Datasource")
    public HikariDataSource readDataSource(HikariConfig test1Config) {
        return new HikariDataSource(test1Config);
    }


    @Bean(name = "test2Config")
    @ConfigurationProperties(prefix = "spring.datasource.test2.hikari")
    public HikariConfig test2Config(){
        return new HikariConfig();
    }
    /**
     * @return javax.sql.DataSource 返回数据源
     * @title 只写数据源
     * @description 只写数据源
     * @author
     * @datetime 2019/12/27 17:25
     */
    @Bean(name = "test2Datasource")
    public HikariDataSource setWriteDataSource(HikariConfig test2Config) {
        return new HikariDataSource(test2Config);
    }



    /**
     * @param dataSource 1 数据源
     * @return org.mybatis.spring.SqlSessionFactoryBean sql
     * @title 根据对应的数据源配置Mapper所有xml路径
     * @description 根据对应的数据源配置Mapper所有xml路径
     * @author
     * @datetime 2019/12/27 17:18
     */
    private SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        // 配置mapper文件位置
        sqlSessionFactoryBean.setMapperLocations(resolver.getResources(mapperLocations));
        return sqlSessionFactoryBean;
    }

    /**
     * @param dynamicDataSource 1 数据源
     * @return org.apache.ibatis.session.SqlSessionFactory
     * @titel 根据对应的数据源配置Mapper所有xml路径
     * @description 根据对应的数据源配置Mapper所有xml路径
     * @author
     * @datetime 2019/10/11
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(dynamicDataSource);
        // 设置mapper.xml的位置路径
        // 配置mapper文件位置
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        factoryBean.setMapperLocations(resolver.getResources(mapperLocations));
        return factoryBean.getObject();
    }

    /**
     * @param dynamicDataSource 1 动态数据源
     * @return org.springframework.transaction.PlatformTransactionManager 返回事务配置
     * @titel 事务配置
     * @description 事务配置
     * @author
     * @datetime 2019/10/11
     */
    @Bean
    public PlatformTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }

    /**
     * @param writeDataSource 2 只写数据源
     * @return javax.sql.DataSource 返回设置数据源对象
     * @titel 初始化SQL会话模板
     * @description 初始化SQL会话模板
     * @author
     */
    @Bean
    public DynamicDataSource dynamicDataSource(@Qualifier("test1Datasource") DataSource writeDataSource,
                                               @Qualifier("test2Datasource") DataSource patentDataDataSource) throws Exception {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetSqlSessionFactorys = new HashMap<Object, Object>();
        targetSqlSessionFactorys.put("test1Datasource", writeDataSource);
        targetSqlSessionFactorys.put("test2Datasource", patentDataDataSource);
        dynamicDataSource.setTargetDataSources(targetSqlSessionFactorys);
        //设置默认数据源
        dynamicDataSource.setDefaultTargetDataSource(writeDataSource);
        return dynamicDataSource;
    }
}

这里需要注意的是使用带配置的DataSource创建方式,也是官方推荐的新建数据源配置方式,可以提前检测出数据库连接池是否能正常建立。

1.6 配置TargetDataSource注解

该注解用于作用在mapper的方法上,通过aop切面的方式去切换数据源

package com.example.springdemo.demo.conifg.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author
 * @ClassName com.framework.common.annotation
 * @Description 数据源注解类
 * @Version 1.0
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface TargetDataSource {
    //默认连接为只读
    String dataSource() default "";
}

1.7 切面方法

package com.example.springdemo.demo.conifg.initDataSourceConfig;

import com.example.springdemo.demo.conifg.annotation.TargetDataSource;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @author
 * @version 1.0
 * @className com.framework.web.config.initDataSourceConfig
 * @description service事物拦截类,用于动态切换数据源
 * @datetime 2019/10/11
 */
@Aspect
//@Order(-1)//必须加上这个不然会DynamicDataSource比DataSourceAspect先执行
@Component
public class DataSourceAspect {

    ///@Before是在所拦截方法执行之前执行一段逻辑。
    // @After 是在所拦截方法执行之后执行一段逻辑。
    // @Around是可以同时在所拦截方法的前后执行一段逻辑。+
    // 作为@Pointcut的参数,用以定义连接点

    /**
     * @titel 配置切面目录
     * @description 配置切面目录
     * @author
     */
    @Pointcut("execution(* com.example.springdemo.demo.dao.*.*(..))")
    public void pointcut() {
    }

    /**
     * @param ds 1 数据源注解
     * @titel 执行方法前更换数据源
     * @description 执行方法前更换数据源
     * @author
     */
    @Before("pointcut() && @annotation(ds)")
    public void beforeDataSource(TargetDataSource ds) {
        String value = ds.dataSource();
        DataSourceContextHolder.setDataSource(value);
    }

    /**
     * @param ds 1 数据源注解
     * @titel 执行方法后清除数据源设置
     * @description 执行方法后清除数据源设置
     * @author
     */
    @After("pointcut() && @annotation(ds)")
    public void afterDataSource(TargetDataSource ds) {
        DataSourceContextHolder.clearDataSource();
    }
}

1.8 dao的写法

如果需要切换数据库的方法,如下加上注解即可切换数据源,否则就是使用默认的数据源,我这里默认数据源为test1source

package com.example.springdemo.demo.dao;

import com.example.springdemo.demo.conifg.annotation.TargetDataSource;
import com.example.springdemo.demo.model.User;
import com.example.springdemo.demo.model.User1;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface UserDao2 {

    @TargetDataSource(dataSource="test2Datasource")
    User getUser();
}

二、测试验证

启动项目前先看看数据库连接有多少
在这里插入图片描述

2.1 启动springboot项目

日志出现以下的日志时候,说明连接池已经建立了。

2023-12-03 16:28:47.354  INFO 7452 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2023-12-03 16:28:47.354  INFO 7452 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1347 ms
2023-12-03 16:28:47.471  INFO 7452 --- [           main] com.zaxxer.hikari.HikariDataSource       : test1pool - Starting...
2023-12-03 16:28:47.627  INFO 7452 --- [           main] com.zaxxer.hikari.HikariDataSource       : test1pool - Start completed.
2023-12-03 16:28:47.652  INFO 7452 --- [           main] com.zaxxer.hikari.HikariDataSource       : test2pool - Starting...
2023-12-03 16:28:47.656  INFO 7452 --- [           main] com.zaxxer.hikari.HikariDataSource       : test2pool - Start completed.

2.2 检查数据库连接

在这里插入图片描述
minimum-idle 这里我两个测试库都是最小连接是2,启动项目后,数据库有4个连接,对得上数量。

2.3 debug看其他数据库属性是否生效

在这里插入图片描述
通过debug到dao这层的请求看代理类的属性,可以看到连接池的属性是否和你配置的一致,只有一致才是读到了配置。

2.4 看请求结果

test1测试结果如下
在这里插入图片描述
test2测试结果如下
在这里插入图片描述
结果是正确切换了数据库并且读取到了数据,测试完毕。

总结

1.这里就不展示如何配置dao了,网上的例子很多,也是该掌握后再看本篇文章。
2.使用切面的方式动态切换数据源,否则就是使用默认的数据源。
3.这里的hikari版本如下,版本变动不大,应该都能一样的使用。

    <dependency>
      <groupId>com.zaxxer</groupId>
      <artifactId>HikariCP</artifactId>
      <version>3.4.5</version>
      <scope>compile</scope>
    </dependency>

4.这里需要注意的是如果方法加上了@Transactional 一个方法里面使用了两个数据源,会导致切换数据源失败,因为
事务的控制也是通过数据源的控制实现的不能同时使用两个数据源,要使用多数据源并且支持事务,只能是使用分布式事务控制了,例如seata等。

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

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

相关文章

SpringBoot项目打jar包

本文章使用idea进行打包 1.打开项目&#xff0c;右击项目选中Open Module Settings进入project Structure&#xff0c;如下图所示&#xff1a; 2.选中Artifacts&#xff0c;点击中间的加号&#xff08;Project Settings->Artifacts->JAR->From modules with dependen…

JavaScript <有道翻译之数据解密‘23年12月06日版‘>--案例(三)

前言: 记得上半年还是去年,有道翻译还是直接返回明文数据;现在也跟着,用接口返回加密数据了; 娱乐一下,破他的密文数据... 成品效果图: js部分: 对于找他的密文数据有点费时,针对密文--->搜他地址和启动器不是特别容易,辗转多时(搜:descrypt/json.parse 结合使用更快),有图…

SpaceSight、Echo 联合升级,打造更懂场景的 AI 「超级门店」

当各领域都在谈论「增长」&#xff0c;门店业务的增长又该从哪里开始着手…… 在日常运营中&#xff0c;「高效」和「细致」是否无法同时实现&#xff1f;「任务下达」和「任务执行」之间有多大偏差&#xff1f; 在客户洞察上&#xff0c;如何用「过去」的数据预测「未来」&…

docker搭建logstash和使用方法

配置logstash 查询下载镜像【固定和elasticsearch一样的版本】 [roothao ~]# docker search logstash NAME DESCRIPTION STARS OFFICIAL AUTOMATED logstash …

CoreDNS实战(五)-接入prometheus监控

1 背景 Prometheus插件作为coredns的Plugins&#xff0c;默认情况下是内置在coredns中&#xff0c;如果是自己编译安装的版本&#xff0c;需要注意在编译安装的时候的plugin.cfg文件中添加了prometheus:metrics&#xff0c;这样才能确保编译成功。 # 首先我们检查一下运行的版…

万亿氢能产业链崛起,汉威科技助力安全发展

近年来化石能源的大量使用带来了碳排放急剧上升、环境污染、极端天气频发、全球变暖等一系列问题&#xff0c;加之化石能源储量日益减少&#xff0c;各国不得不考虑重构能源体系&#xff0c;寻找化石能源的替代方案&#xff0c;努力降低碳排放。 在此背景下&#xff0c;氢能成…

gmid方法设计五管OTA二级远放

首先给出第一级是OTA&#xff0c;第二级是CS的二级运放电路图&#xff1a; gmid的设计方法可以根据GBW、Av、CL来进行电路设计&#xff0c;因此在设计电路之前需要以上的参数要求。 1、为了满足电路的相位裕度至少60&#xff0c;需要对GBW、主极点、零点进行分析。 首先给出其…

Python Dask库:大数据处理的利器

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Dask是一个灵活、开源的Python库&#xff0c;专为处理大规模数据集而设计。与传统的单机计算相比&#xff0c;Dask能够在分布式系统上运行&#xff0c;有效利用集群的计算资源。本文将深入介绍Dask的核心概念、功…

近期Google paly再次卡审?需要开发者提供更多关于应用的信息以通过谷歌审查?

谷歌政策更新得越来越频繁&#xff0c;也越来越严格&#xff0c;加大了对应用的审核力度。 最近&#xff0c;不少开发者表示&#xff0c;谷歌卡审又出新花样了。与之前收到暂停审核电话验证邮件&#xff08;需要在48-72小时内&#xff0c;拨打你开发者账号的号码&#xff0c;应…

IDEA 修改encoding

IDEA 修改encoding 现象&#xff1a;idea展示乱码 打开Settings>>File Encodings&#xff0c;修改为UTF-8即可

ahk系列-windows超级运行框-表达式计算(12)—功能汇总

1、环境准备 windows 7&#xff0c;8&#xff0c;10&#xff0c;11操作系统ahk 2.x_64位翻译功能需要联网使用 2、使用方式 输入winR打开windows运行框 get/getpath 命令获取配置文件环境变量set/sets 设置 “用户/系统” 环境变量或者pathencode/decode 中文编码和解码len…

Ubuntu-Sim2Real环境配置(下)

cd ICRA-RM-Sim2Real/docker_client/ ./exec_client.sh cd ~ roslaunch rtab_navigation rtab_navigation.launch 执行上面代码的时候后台一直刷新 cd ICRA-RM-Sim2Real/docker_client/ ./exec_client.sh cd ~ roslaunch carto_navigation navigation.launch 1.Usage 执行该…

❀My学习Linux命令小记录(16)❀

目录 ❀My学习Linux命令小记录&#xff08;16&#xff09;❀ 61.who指令 62.sleep指令 63.kill指令 64.top指令 65.diff指令 ❀My学习Linux命令小记录&#xff08;16&#xff09;❀ 61.who指令 功能说明&#xff1a;显示目前登录系统的用户信息。 &#xff08;ps.who命…

Python sorted函数及用法以及如何用json模块存储数据

Python sorted函数及用法 sorted() 函数与 reversed() 函数类似&#xff0c;该函数接收一个可迭代对象作为参数&#xff0c;返回一个对元素排序的列表。 在交互式解释器中测试该函数&#xff0c;可以看到如下运行过程&#xff1a; >>> a [20, 30, -1.2, 3.5, 90, 3.…

阿里大佬讲解的接口自动化测试框架pytest系列——pluggy插件源码解读:hook钩子函数调用执行过程分析

经过pluggy源码解读系列1-4的分析&#xff0c;已经完成插件定义、spec定义&#xff0c;插件注册等环节&#xff0c;下面就到了调用插件执行了&#xff0c;即hook钩子函数是如何被调用执行的&#xff0c;下面还是先把pluggy使用的代码放下面&#xff1a; import pluggy# Hooksp…

PIKA,一个神奇的AI工具

随着人工智能技术的不断发展&#xff0c;越来越多的创新性工具开始涌现&#xff0c;为各行各业带来了巨大的变革。其中&#xff0c;视频生成AI工具PIKA&#xff0c;以其独特的功能和广泛的应用领域&#xff0c;吸引了众多用户的关注。本文将详细介绍PIKA的功能、特点以及应用前…

PyQt6 QGroupBox分组框控件

​锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计37条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话…

大话数据结构-查找-有序表查找

注&#xff1a;本文同步发布于稀土掘金。 3 有序表查找 3.1 折半查找 折半查找&#xff08;Binary Search&#xff09;技术&#xff0c;又称为二分查找&#xff0c;它的前提是线性表中的记录必须是关键码有序&#xff08;通常从小到大有序&#xff09;&#xff0c;线性表必须…

【Vue3从入门到项目实现】RuoYi-Vue3若依框架前端学习——登录页面

若依官方的前后端分离版中&#xff0c;前端用的Vue2&#xff0c;这个有人改了Vue3的前端出来。刚好用来学习&#xff1a; https://gitee.com/weifengze/RuoYi-Vue3 运行前后端项目 首先运行项目 启动前端&#xff0c;npm install、npm run dev 启动后端&#xff0c;按教程配置…

信息系统安全运维服务资质认证申报流程详解

随着我国信息化和信息安全保障工作的不断深入&#xff0c;以应急处理、风险评估、灾难恢复、系统测评、安全运维、安全审计、安全培训和安全咨询等为主要内容的信息安全服务在信息安全保障中的作用日益突出。加强和规范信息安全服务资质管理已成为信息安全管理的重要基础性工作…