解决SpringBoot项目整合Sharding-JDBC后启动慢的问题

news2024/11/28 13:34:03

一、问题描述

线上某一项目以jar包的方式发布,需要健康检查,若15次健康检查页面状态均为非200则健康检查失败,就会导致tomcat服务加载失败。前几天版本迭代,发布该项目时,因最后一次健康检查的时间比启动完成时早,所以认为启动失败,导致该项目未发布成功。

二、分析定位

项目以war包方式启动和jar包方式启动在开启8080端口的时间点上不一样。以war包的方式启动是在应用启动时就开启8080端口,此时应用还没启动成功,虽然健康检查接口访问不了,但因为端口是开的,所以Rundeck访问健康检查接口时会卡住,直到自行超时,所以整个健康检查的过程会被应用启动成功前的超时时间拉长。而以jar的方式启动,在应用启动成功之后才开启8080端口,在应用没启动成功前,Rundeck访问健康检查接口会直接报地址无法访问,一旦应用启动时间稍长,就会很快把Rundeck健康检查重试次数耗完,之后就认为启动失败了。

解决方法:

  1. 可以修改Rundeck启动超时时间。以上例为例,之前Rundeck超时时间是1分钟,可以修改为2分钟。

  1. 优化Sharding-JDBC。

方法一没什么好说的,肯定能解决问题。下面说下方法二,不仅能解决问题,同时也能让我们在本地启动项目时更快些。

二、背景

SringBoot版本:2.3.3.RELEASE

ShardingSphere版本:5.0.0

数据源连接池:Druid

数据库数为5,逻辑库名分别为dbm,db0,db1,db2,db3。其中dbm中存放单表(即不分库分表的表),db0~db3库用于分库。每个需要分库分表的表,按4库50表根据自定义分库分表算法进行水平切分。该项目单表数量为11,需要进行分库分表的表的数量为8。

配置文件大致如下:

# 数据源参数配置
initialSize=5
minIdle=5
maxIdle=100
maxActive=20
maxWait=60000
timeBetweenEvictionRunsMillis=60000
minEvictableIdleTimeMillis=300000
# Sharding Jdbc配置
# 分库的数量(注意:需要排除主库)
databaseSize=4
# 分表的数量
tableSize=50
# dbm为主库,db0,db1,db2,db3
spring.shardingsphere.datasource.names=dbm,db0,db1,db2,db3
# 配置主库
spring.shardingsphere.datasource.dbm.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.dbm.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.dbm.url=jdbc:mysql://ip:3306/rt_warehouse_inventory?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&tinyInt1isBit=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.dbm.username=username
spring.shardingsphere.datasource.dbm.password=password
spring.shardingsphere.datasource.dbm.initialSize=${initialSize}
spring.shardingsphere.datasource.dbm.minIdle=${minIdle}
spring.shardingsphere.datasource.dbm.maxActive=${maxActive}
spring.shardingsphere.datasource.dbm.maxWait=${maxWait}
spring.shardingsphere.datasource.dbm.validationQuery=SELECT 1 FROM DUAL
spring.shardingsphere.datasource.dbm.timeBetweenEvictionRunsMillis=${timeBetweenEvictionRunsMillis}
spring.shardingsphere.datasource.dbm.minEvictableIdleTimeMillis=${minEvictableIdleTimeMillis}
# 配置db0
spring.shardingsphere.datasource.db0.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db0.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db0.url=jdbc:mysql://ip:3306/rt_warehouse_inventory_00?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&tinyInt1isBit=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.db0.username=username
spring.shardingsphere.datasource.db0.password=password
spring.shardingsphere.datasource.db0.initialSize=${initialSize}
spring.shardingsphere.datasource.db0.minIdle=${minIdle}
spring.shardingsphere.datasource.db0.maxActive=${maxActive}
spring.shardingsphere.datasource.db0.maxWait=${maxWait}
spring.shardingsphere.datasource.db0.validationQuery=SELECT 1 FROM DUAL
spring.shardingsphere.datasource.db0.timeBetweenEvictionRunsMillis=${timeBetweenEvictionRunsMillis}
spring.shardingsphere.datasource.db0.minEvictableIdleTimeMillis=${minEvictableIdleTimeMillis}
# 配置db1
spring.shardingsphere.datasource.db1.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db1.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db1.url=jdbc:mysql://ip:3306/rt_warehouse_inventory_01?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&tinyInt1isBit=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.db1.username=username
spring.shardingsphere.datasource.db1.password=password
spring.shardingsphere.datasource.db1.initialSize=${initialSize}
spring.shardingsphere.datasource.db1.minIdle=${minIdle}
spring.shardingsphere.datasource.db1.maxActive=${maxActive}
spring.shardingsphere.datasource.db1.maxWait=${maxWait}
spring.shardingsphere.datasource.db1.validationQuery=SELECT 1 FROM DUAL
spring.shardingsphere.datasource.db1.timeBetweenEvictionRunsMillis=${timeBetweenEvictionRunsMillis}
spring.shardingsphere.datasource.db1.minEvictableIdleTimeMillis=${minEvictableIdleTimeMillis}
# 配置db2
spring.shardingsphere.datasource.db2.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db2.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db2.url=jdbc:mysql://ip:3306/rt_warehouse_inventory_02?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&tinyInt1isBit=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.db2.username=username
spring.shardingsphere.datasource.db2.password=password
spring.shardingsphere.datasource.db2.initialSize=${initialSize}
spring.shardingsphere.datasource.db2.minIdle=${minIdle}
spring.shardingsphere.datasource.db2.maxActive=${maxActive}
spring.shardingsphere.datasource.db2.maxWait=${maxWait}
spring.shardingsphere.datasource.db2.validationQuery=SELECT 1 FROM DUAL
spring.shardingsphere.datasource.db2.timeBetweenEvictionRunsMillis=${timeBetweenEvictionRunsMillis}
spring.shardingsphere.datasource.db2.minEvictableIdleTimeMillis=${minEvictableIdleTimeMillis}
# 配置db3
spring.shardingsphere.datasource.db3.type=com.alibaba.druid.pool.DruidDataSource
spring.shardingsphere.datasource.db3.driver-class-name=com.mysql.cj.jdbc.Driver
spring.shardingsphere.datasource.db3.url=jdbc:mysql://ip:3306/rt_warehouse_inventory_03?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false&tinyInt1isBit=false&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghai
spring.shardingsphere.datasource.db3.username=username
spring.shardingsphere.datasource.db3.password=password
spring.shardingsphere.datasource.db3.initialSize=${initialSize}
spring.shardingsphere.datasource.db3.minIdle=${minIdle}
spring.shardingsphere.datasource.db3.maxActive=${maxActive}
spring.shardingsphere.datasource.db3.maxWait=${maxWait}
spring.shardingsphere.datasource.db3.validationQuery=SELECT 1 FROM DUAL
spring.shardingsphere.datasource.db3.timeBetweenEvictionRunsMillis=${timeBetweenEvictionRunsMillis}
spring.shardingsphere.datasource.db3.minEvictableIdleTimeMillis=${minEvictableIdleTimeMillis}
# 分库配置
spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-column=store_no
spring.shardingsphere.rules.sharding.default-database-strategy.standard.sharding-algorithm-name=preciseShardingDatabaseAlgorithm
# 分表配置
# test1表配置
spring.shardingsphere.rules.sharding.tables.test1.actual-data-nodes=db$->{0..3}.test1_0$->{0..9},db$->{0..3}.test1_$->{10..49}
spring.shardingsphere.rules.sharding.tables.test1.table-strategy.standard.sharding-column=store_no
spring.shardingsphere.rules.sharding.tables.test1.table-strategy.standard.sharding-algorithm-name=preciseShardingTableAlgorithm
# test2表配置
spring.shardingsphere.rules.sharding.tables.test2.actual-data-nodes=db$->{0..3}.test2_0$->{0..9},db$->{0..3}.test2_$->{10..49}
spring.shardingsphere.rules.sharding.tables.test2.table-strategy.standard.sharding-column=store_no
spring.shardingsphere.rules.sharding.tables.test2.table-strategy.standard.sharding-algorithm-name=preciseShardingTableAlgorithm
# test3表配置
spring.shardingsphere.rules.sharding.tables.test3.actual-data-nodes=db$->{0..3}.test3_0$->{0..9},db$->{0..3}.test3_$->{10..49}
spring.shardingsphere.rules.sharding.tables.test3.table-strategy.standard.sharding-column=store_no
spring.shardingsphere.rules.sharding.tables.test3.table-strategy.standard.sharding-algorithm-name=preciseShardingTableAlgorithm
# test4表配置
spring.shardingsphere.rules.sharding.tables.test4.actual-data-nodes=db$->{0..3}.test4_0$->{0..9},db$->{0..3}.test4_$->{10..49}
spring.shardingsphere.rules.sharding.tables.test4.table-strategy.standard.sharding-column=store_no
spring.shardingsphere.rules.sharding.tables.test4.table-strategy.standard.sharding-algorithm-name=preciseShardingTableAlgorithm
# test5表配置
spring.shardingsphere.rules.sharding.tables.test5.actual-data-nodes=db$->{0..3}.test5_0$->{0..9},db$->{0..3}.test5_$->{10..49}
spring.shardingsphere.rules.sharding.tables.test5.table-strategy.standard.sharding-column=store_no
spring.shardingsphere.rules.sharding.tables.test5.table-strategy.standard.sharding-algorithm-name=preciseShardingTableAlgorithm
# test6表配置
spring.shardingsphere.rules.sharding.tables.test6.actual-data-nodes=db$->{0..3}.test6_0$->{0..9},db$->{0..3}.test6_$->{10..49}
spring.shardingsphere.rules.sharding.tables.test6.table-strategy.standard.sharding-column=store_no
spring.shardingsphere.rules.sharding.tables.test6.table-strategy.standard.sharding-algorithm-name=preciseShardingTableAlgorithm
# test7表配置
spring.shardingsphere.rules.sharding.tables.test7.actual-data-nodes=db$->{0..3}.test7_0$->{0..9},db$->{0..3}.test7_$->{10..49}
spring.shardingsphere.rules.sharding.tables.test7.table-strategy.standard.sharding-column=store_no
spring.shardingsphere.rules.sharding.tables.test7.table-strategy.standard.sharding-algorithm-name=preciseShardingTableAlgorithm
# test8表配置
spring.shardingsphere.rules.sharding.tables.test8.actual-data-nodes=db$->{0..3}.test8_0$->{0..9},db$->{0..3}.test8_$->{10..49}
spring.shardingsphere.rules.sharding.tables.test8.table-strategy.standard.sharding-column=store_no
spring.shardingsphere.rules.sharding.tables.test8.table-strategy.standard.sharding-algorithm-name=preciseShardingTableAlgorithm

# 打印分库分表日志
spring.shardingsphere.props.sql-show=true

本地测试十次启动时间,启动时间如下图:

启动次数

第一次

第二次

第三次

第四次

第五次

第六次

第七次

第八次

第九次

第十次

启动时间

29.625s

23.748s

24.299s

22.575s

24.167s

23.13s

23.73s

23.419s

22.91s

23.04s

二、优化方式

先来看下在启动时,ShardingSphere-JDBC如何加载单表规则。

首先在创建单表规则SingleTableRule时,通过getAggregateDataSourceMap方法获取所有数据源。以本例为例,即通过该方法将获取dbm,db0,db1,db2,db3数据源。然后通过单表数据节点加载器加载所有数据源中的单表。其中通过getExcludedTables(builtRules)方法获取所有数据分片的表,包括逻辑表名和真实表名。如下图:

然后循环遍历所有数据源,首先加载每个数据源的所有表名,然后判断改表是否是要数据分片的表,若不是,则即是单表,根据该单表名和数据源逻辑名创建单表数据节点。如前所述,对于dbm数据源,我们只存放单表,共11张表,通过SingleTableDataNodeLoader.loadAllTableNames方法即获得11张单表,循环遍历11次,并且这11张表不在excludedTables(需要数据分片的表名,本例共8个表需要数据分片,每个表水平切分50个真实表,加上逻辑表名,共408个表名,为test1,test2,test3,test4,test5,test6,test7,test8,test1_00~test1_19,test2_00~test2_19,test3_00~test3_19,test4_00~test4_19,test5_00~test5_19,test6_00~test6_19,test7_00~test7_19,test8_00~test8_19)中,根据这11个单表表明和dbm数据源创建11个单表数据节点,本次循环结束。对于db0数据源,共存放8 * 50 共400张真实表,表名为test1_00~test1_19,test2_00~test2_19,test3_00~test3_19,test4_00~test4_19,test5_00~test5_19,test6_00~test6_19,test7_00~test7_19,test8_00~test8_19。通过SingleTableDataNodeLoader.loadAllTableNames方法即获得上述400个表名,循环遍历400次,判断表明是否存在于excludedTables中,显然时存在的。显然这400次循环遍历判断是多余的,因为单表只存在于dbm中,db0中只存在数据分片的表,且肯定存在excludedTables中。对于db1、db2、db3同理。源码如下图:

通过上面分析可知,对于我这个项目的实际情况,单表只在dbm中,在加载单表时完全不用去db0~db3数据源中去加载。显然这块共四次加载所有表名及4*400=1600次循环判断是多余的。若数据源增多或者需要数据分片的表增多,在上述多余的步骤上耗时也会变多,项目启动会变的更慢。可以通过修改getAggregateDataSourceMap方法,只获取dbm数据源来优化启动时间。

具体优化方式如下:

  1. 使用HikariCP数据源连接池替换Druid数据源连接池。

  1. 在应用里建一个和SingleTableRule类相同名称且路路径相同的文件,将下面内容拷贝进去,这样不会动到原jar包。下面内容就是将getAggregateDataSourceMap方法替换为getMasterDataSourceMap方法,只获取dbm数据源。

package org.apache.shardingsphere.singletable.rule;

import lombok.Getter;
import org.apache.shardingsphere.infra.config.properties.ConfigurationProperties;
import org.apache.shardingsphere.infra.database.type.DatabaseType;
import org.apache.shardingsphere.infra.datanode.DataNode;
import org.apache.shardingsphere.infra.route.context.RouteContext;
import org.apache.shardingsphere.infra.route.context.RouteUnit;
import org.apache.shardingsphere.infra.rule.ShardingSphereRule;
import org.apache.shardingsphere.infra.rule.identifier.scope.SchemaRule;
import org.apache.shardingsphere.infra.rule.identifier.type.DataNodeContainedRule;
import org.apache.shardingsphere.infra.rule.identifier.type.DataSourceContainedRule;
import org.apache.shardingsphere.infra.rule.identifier.type.MutableDataNodeRule;
import org.apache.shardingsphere.infra.rule.identifier.type.TableContainedRule;

import javax.sql.DataSource;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * Single table rule.
 */
@Getter
public final class SingleTableRule implements SchemaRule, DataNodeContainedRule, TableContainedRule, MutableDataNodeRule {

    private final Collection<String> dataSourceNames;

    private final Map<String, SingleTableDataNode> singleTableDataNodes;

    public SingleTableRule(final DatabaseType databaseType, final Map<String, DataSource> dataSourceMap, final Collection<ShardingSphereRule> builtRules, final ConfigurationProperties props) {
        Map<String, DataSource> aggregateDataSourceMap = getMaterDataSourceMap(dataSourceMap);
        dataSourceNames = aggregateDataSourceMap.keySet();
        singleTableDataNodes = SingleTableDataNodeLoader.load(databaseType, aggregateDataSourceMap, getExcludedTables(builtRules), props);
    }

    // 只获取主数据库数据源
    private Map<String, DataSource> getMasterDataSourceMap(final Map<String, DataSource> dataSourceMap) {
        Map<String, DataSource> result = new LinkedHashMap<>(1);
        for (Entry<String, DataSource> entry : dataSourceMap.entrySet()) {
            String logicName = entry.getKey();
            if (logicName != null) {
                result.put(logicName,dataSourceMap.get(logicName));
            }
            break;
        }
        return result;
    }

    /**
     * Judge whether single tables are in same data source or not.
     *
     * @param singleTableNames single table names
     * @return whether single tables are in same data source or not
     */
    public boolean isSingleTablesInSameDataSource(final Collection<String> singleTableNames) {
        Set<String> dataSourceNames = singleTableNames.stream().map(singleTableDataNodes::get).filter(Objects::nonNull).map(SingleTableDataNode::getDataSourceName).collect(Collectors.toSet());
        return dataSourceNames.size() <= 1;
    }

    /**
     * Judge whether all tables are in same data source or not.
     *
     * @param routeContext route context
     * @param singleTableNames single table names
     * @return whether all tables are in same data source or not
     */
    public boolean isAllTablesInSameDataSource(final RouteContext routeContext, final Collection<String> singleTableNames) {
        if (!isSingleTablesInSameDataSource(singleTableNames)) {
            return false;
        }
        SingleTableDataNode dataNode = singleTableDataNodes.get(singleTableNames.iterator().next());
        for (RouteUnit each : routeContext.getRouteUnits()) {
            if (!each.getDataSourceMapper().getLogicName().equals(dataNode.getDataSourceName())) {
                return false;
            }
        }
        return true;
    }

    /**
     * Get sharding logic table names.
     *
     * @param logicTableNames logic table names
     * @return sharding logic table names
     */
    public Collection<String> getSingleTableNames(final Collection<String> logicTableNames) {
        return logicTableNames.stream().filter(singleTableDataNodes::containsKey).collect(Collectors.toCollection(LinkedList::new));
    }

    @Override
    public void addDataNode(final String tableName, final String dataSourceName) {
        if (dataSourceNames.contains(dataSourceName) && !singleTableDataNodes.containsKey(tableName)) {
            singleTableDataNodes.put(tableName, new SingleTableDataNode(tableName, dataSourceName));
        }
    }

    @Override
    public void dropDataNode(final String tableName) {
        singleTableDataNodes.remove(tableName);
    }

    private Collection<String> getExcludedTables(final Collection<ShardingSphereRule> rules) {
        return rules.stream().filter(each -> each instanceof DataNodeContainedRule).flatMap(each -> ((DataNodeContainedRule) each).getAllTables().stream()).collect(Collectors.toSet());
    }

    @Override
    public Map<String, Collection<DataNode>> getAllDataNodes() {
        return singleTableDataNodes.values().stream().map(each -> new DataNode(each.getDataSourceName(), each.getTableName()))
                .collect(Collectors.groupingBy(DataNode::getTableName, LinkedHashMap::new, Collectors.toCollection(LinkedList::new)));
    }

    @Override
    public Collection<String> getAllActualTables() {
        return Collections.emptyList();
    }

    @Override
    public Optional<String> findFirstActualTable(final String logicTable) {
        return Optional.empty();
    }

    @Override
    public boolean isNeedAccumulate(final Collection<String> tables) {
        return false;
    }

    @Override
    public Optional<String> findLogicTableByActualTable(final String actualTable) {
        return Optional.empty();
    }

    @Override
    public Optional<String> findActualTableByCatalog(final String catalog, final String logicTable) {
        return Optional.empty();
    }

    @Override
    public Collection<String> getAllTables() {
        return singleTableDataNodes.keySet();
    }

    @Override
    public Collection<String> getTables() {
        return singleTableDataNodes.keySet();
    }

    @Override
    public String getType() {
        return SingleTableRule.class.getSimpleName();
    }
}

优化后本地测试十次启动时间,启动时间如下图

启动次数

第一次

第二次

第三次

第四次

第五次

第六次

第七次

第八次

第九次

第十次

启动时间

15.231s

17.426s

16.395s

16.19s

17.029s

15.169s

15.025s

15.559s

14.975s

14.699s

通过优化前后本地启动时间对比可以看出应用启动明显快了些。

该方式适用于ShardingSphere版本:5.0.0和5.2.0版本,只在这两个正在使用的版本上验证了下,其他版本并未验证是否可行。

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

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

相关文章

练习时长两年半的tcp三次握手

1、TCP是什么&#xff1f;TCP是面向连接的协议&#xff0c;它基于运输连接来传送TCP报文段&#xff0c;TCP运输连接的建立和释放&#xff0c;是每一次面向连接的通信中必不可少的过程。TCP运输连接有以下三个阶段&#xff1a;建立TCP连接&#xff0c;也就是通过三报文握手来建立…

Oracle打补丁

oralce打补丁 打补丁前提&#xff1a; 一、备份数据库 二、将oracle服务全部停掉 1、查看opatch的版本号 1.1、环境变量配置ORACLE_HOME 1.2、运行opatch version命令&#xff0c;查看opatch的版本号 备注&#xff1a;网上查看opatch的版本号对应的oracle是否匹配&#xff0c;…

【分治策略】查询中位数最接近点对

查询中位数给定线性序集中n个元素和一个整数k 【k(n1)/2】&#xff0c;要求找出这n个元素中第k小的元素&#xff0c;即找中位数。线性序列没有排序,没有重复值。已知快速排序划分时一个划分基准数的位置在确定后&#xff0c;在之后排序中是不会变的。利用此特性&#xff0c;以下…

dataphin如何使用zip文件,离线安装python第三方包?

好久没写文章啦&#xff0c;快过年了啦&#xff0c;打工人要回家啦 背景介绍&#xff1a; 每次在dataphin里使用pandas的时候&#xff0c;都要pip install pandas。dataphin需要下载pandas安装包&#xff0c;比较费时。总而言之&#xff0c;这种方式慢。 所以我要在dataphin的…

【手写 Vue2.x 源码】第十四篇 - 生成 ast 语法树 - 模板解析

一&#xff0c;前言 上篇&#xff0c;主要介绍了生成 ast 语法树-正则说明部分&#xff0c;涉及以下几个点&#xff1a; 简要说明了 HTML模板的解析方式对模板解析相关正则说明和测试 本篇&#xff0c;生成 ast 语法树-代码实现 二&#xff0c;模板解析 模板解析的方式&…

22. 听说你想要用爬虫采集我的手机号?哎 ~ 我展示用的是图片

本篇博客我们实现图片渲染手机号码案例&#xff0c;用于防止爬虫直接采集文字信息。 爬虫训练场 本案例实现的效果如下所示 文章目录bootstrap5 实现名片样式卡片补充数据生成逻辑生成用户 5 个汉字的昵称调用头像 API&#xff0c;生成图片将手机号码生成图片bootstrap5 实现名…

菜鸡二次封装element中table表单

实现效果如下封装的table表单<template><el-table:span-method"arraySpanMethod":header-cell-style"rowClass":cell-style"cellStyle":data"tableData"style"width: 100%; height: 100%">//暂无数据展示<te…

汤姆斯的天堂梦(C++,Dijkstra)

题目描述 汤姆斯生活在一个等级为 000 的星球上。那里的环境极其恶劣&#xff0c;每天 121212 小时的工作和成堆的垃圾让人忍无可忍。他向往着等级为 NNN 的星球上天堂般的生活。 有一些航班将人从低等级的星球送上高一级的星球&#xff0c;有时需要向驾驶员支付一定金额的费…

【跟月影学可视化】学习笔记 41 篇(完结)

说明 【跟月影学可视化】专栏学习笔记。 个人学习笔记源码&#xff1a;https://github.com/kaimo313/visual-learning-demo 一共做了 162 个学习示例以及 41 篇博客学习笔记&#xff0c;要深入学习该课程请支持正版&#xff0c;个人笔记仅供参考。 笔记目录 【图形基础篇…

什么是无源相干定位系统?

无源定位&#xff08;Passive Localization&#xff09;不通过发射信号来探测目标的位置&#xff0c;而是接收目标的有意、无意辐射或反射信号来实现对侦察目标的探测、定位与追踪。接收的信号可以是目标直接辐射的信号&#xff0c;也可以是外辐射源照射到目标后反射或散射的信…

网站关键词怎么优化排名(网站关键词通常可以选择哪些词)

网站核心关键词的选取需要具备哪些条件 在对网站优化的过程中&#xff0c;肯定少不了对网站关键词的选取&#xff0c;关键词的选择又是网站优化中十分重要的一步&#xff0c;那么网站在选择关键词的过程中需要遵循哪些原则呢&#xff1f;关于这个问题老张带你了解一下。 1、首…

wav文件格式分析与详解

wav文件格式分析与详解WAV文件是在PC机平台上很常见的、最经典的多媒体音频文件,最早于1991年8月出现在Windows 3.1操作系统上,文件扩展名为WAV,是WaveFom的简写,也称为波形文件,可直接存储声音波形,还原的波形曲线十分逼真。WAV文件格式简称WAV格式是一种存储声音波形的数字音…

Wijmo 2022 v2 JavaScript UI Crack

Wijmo 2022 v2 采集 by Ω578867473 添加对 Angular 14 和 React 18 的支持以及对 FlexGrid 和 FlexChart 的改进。特征 Angular 14 支持——您今天就可以开始将 Angular 14 应用程序与 Wijmo 结合使用。Wijmo 提供了大量快速、灵活的 Angular 组件&#xff0c;每个组件都有丰富…

【学Vue就跟玩一样】组件-非单文件组件的使用

一&#xff0c;什么是组件实现应用中局部功能代和资源的集合&#xff08;简单来说就是将html&#xff0c;js&#xff0c;css&#xff0c;资源整合起来的一个小盒子&#xff09;理解&#xff1a;用来实现局部(特定)功能效果的代码集合为什么&#xff1a;一个界面的功能很复杂作用…

SD卡损坏了怎么办?sd卡恢复,80%的用户都试过这些方法

SD卡作为一种外部存储设备&#xff0c;多用在数据相机、监控、手机、无人机等设备中&#xff0c;可以帮我们保存很多数据。 但是SD卡也跟其他设备一样&#xff0c;容易发生数据丢失的情况。如果SD卡损坏了&#xff0c;或者我们把里面的数据误删或者格式化&#xff0c;sd卡恢复…

MySQL--什么情况下不建议使用join查询

关于join 当需要查询两个表的交集、并集等数据时&#xff0c;除了嵌套子查询的方式外&#xff0c;还可以使用join的方式提升性能。对于MySQL的join语句&#xff0c;需要两个最基础的“角色”&#xff1a;主表即驱动表&#xff0c;关联表即驱动表。join描述的就是驱动表与被驱动…

云服务器怎样搭建静态网站?

先买好域名和云服务器&#xff0c;然后把云服务器的ip地址和域名解析到一起。 然后登陆云服务器&#xff0c;安装Nginx 我的软件环境是 CentOS 1、安装 Nginx 在 CentOS 上&#xff0c;可直接使用 yum 来安装 Nginx&#xff08;安装时间稍微有点长&#xff0c;安装过程中代码会…

Linux应用编程---10.信号量

Linux应用编程—10.信号量 ​ 信号量用于任务间的同步!简单来理解&#xff0c;信号量是一个被内核维护的整数&#xff0c;这个整数一般是“大于等于零”的&#xff0c;我们对这个信号量的操作一般为&#xff1a;将信号量设置一个值、发布(加上一个信号量)、消耗(减去一个信号量…

LINUX提权之计划任务提权篇

前言 今天给大家带来的是计划任务提权&#xff0c;说起定时任务对于linux很熟悉的小伙伴一定不会陌生&#xff0c;但你有没有想过可以通过定时任务来进行权限提升的操作&#xff0c;本文会根据该知识点进行展开&#xff0c;同时给大家介绍一个用于探测漏洞的工具使用方法&…

线程通信:生产者消费者问题

问题 1.生产者&#xff08;Producer&#xff09;将产品给店员&#xff08;Clerk&#xff09;&#xff0c;而消费者&#xff08;Customer&#xff09;从店员处取走产品&#xff0c;店员一次只能持有固定数量的产品&#xff08;比如&#xff1a;20&#xff09; &#xff0c;如果生…