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

编程修炼之Hibernate--- springboot启动初始化ddl过程与如何自定义修改 table 字段长度

文章目录

  • springboot启动初始化ddl过程
  • 如何自定义修改 table

springboot启动初始化ddl过程

跟踪Springboot整合hibernate的启动代码:
在这里插入图片描述
SessionFactoryImpl 的初始化里做了非常多的事情,初始化各种资源,并调用 SchemaManagementToolCoordinator.process 先执行脚本任务再执行 Db任务:

		performScriptAction( actions.getScriptAction(), metadata, tool, serviceRegistry, executionOptions, configService );performDatabaseAction( actions.getDatabaseAction(), metadata, tool, serviceRegistry, executionOptions );

在这里插入图片描述
在这里就开始进行 spring.jpa.hibernate.ddl-auto 配置的项,进行处理了。
在这里插入图片描述
在 doMigration 时,就获取到 tables 的元数据:

public class GroupedSchemaMigratorImpl extends AbstractSchemaMigrator {public GroupedSchemaMigratorImpl(HibernateSchemaManagementTool tool, SchemaFilter schemaFilter) {super(tool, schemaFilter);}protected NameSpaceTablesInformation performTablesMigration(Metadata metadata, DatabaseInformation existingDatabase, ExecutionOptions options, Dialect dialect, Formatter formatter, Set<String> exportIdentifiers, boolean tryToCreateCatalogs, boolean tryToCreateSchemas, Set<Identifier> exportedCatalogs, Namespace namespace, GenerationTarget[] targets) {NameSpaceTablesInformation tablesInformation = new NameSpaceTablesInformation(metadata.getDatabase().getJdbcEnvironment().getIdentifierHelper());if (this.schemaFilter.includeNamespace(namespace)) {this.createSchemaAndCatalog(existingDatabase, options, dialect, formatter, tryToCreateCatalogs, tryToCreateSchemas, exportedCatalogs, namespace, targets);NameSpaceTablesInformation tables = existingDatabase.getTablesInformation(namespace);Iterator var14 = namespace.getTables().iterator();Table table;TableInformation tableInformation;while(var14.hasNext()) {table = (Table)var14.next();if (this.schemaFilter.includeTable(table) && table.isPhysicalTable()) {this.checkExportIdentifier(table, exportIdentifiers);tableInformation = tables.getTableInformation(table);if (tableInformation == null) {this.createTable(table, dialect, metadata, formatter, options, targets);} else if (tableInformation != null && tableInformation.isPhysicalTable()) {tablesInformation.addTableInformation(tableInformation);this.migrateTable(table, tableInformation, dialect, metadata, formatter, options, targets);}}}var14 = namespace.getTables().iterator();while(true) {do {do {do {if (!var14.hasNext()) {return tablesInformation;}table = (Table)var14.next();} while(!this.schemaFilter.includeTable(table));} while(!table.isPhysicalTable());tableInformation = tablesInformation.getTableInformation(table);} while(tableInformation != null && (tableInformation == null || !tableInformation.isPhysicalTable()));this.applyIndexes(table, tableInformation, dialect, metadata, formatter, options, targets);this.applyUniqueKeys(table, tableInformation, dialect, metadata, formatter, options, targets);}} else {return tablesInformation;}}
}

如何自定义修改 table

再往下的过程,到 HibernateSchemaManagementTool 这个核心类:
在这里插入图片描述
ddl-auto 语义的实现,就在这里。
那要自定义修改 table ,最常见的需要就是 hibernate 只能增加,对于修改字段长度这一类的涉及不到。当然这种修改只限于开发技术交流,生产环境慎用。
回归正题,要想修改字段长度有这么几个关键数据:

  • table 的元数据
  • Entity 的元数据
    hibernate 本身的功能,如 Migrator 既然能识别到字段缺失,那肯定也能获取到这2个元数据。也就是2个参数:registry 和 metadata。
    了解了需要的数据,就有了思路:
public void migrateDB(DataSourceProperties dataSource, EntityManager entityManager, String ddlAuto, String dialectStr) {log.info("schema 生成:{}", dataSource.getUrl());Set<EntityType<?>> entities = entityManager.getMetamodel().getEntities();Properties p = new Properties();// 数据库方言,最终输出的方言p.put(AvailableSettings.DIALECT, dialectStr);// 自动执行的动作p.put(AvailableSettings.HBM2DDL_AUTO, ddlAuto);// 分隔符,默认为空p.put(AvailableSettings.HBM2DDL_DELIMITER, ";");// 是否展示SQLp.put(AvailableSettings.SHOW_SQL, true);p.put("hibernate.connection.driver_class", dataSource.getDriverClassName());p.put("hibernate.connection.url", dataSource.getUrl());p.put("hibernate.connection.username", dataSource.getUsername());p.put("hibernate.connection.password", dataSource.getPassword());// 是否使用默认的jdbc元数据,默认为true,读取项目自身的元数据p.put("hibernate.temp.use_jdbc_metadata_defaults", true);
//                p.put("hibernate.temp.use_jdbc_metadata_defaults", false);ConfigurationHelper.resolvePlaceHolders(p);try (ServiceRegistry registry = new StandardServiceRegistryBuilder().applySettings(p).build()) {Map settings = registry.getService(ConfigurationService.class).getSettings();MetadataSources metadataSources = new MetadataSources(registry);entities.forEach(entityType -> metadataSources.addAnnotatedClass(entityType.getJavaType()));Metadata metadata = metadataSources.buildMetadata();HashMap properties = new HashMap<>();properties.putAll(registry.getService(ConfigurationService.class).getSettings());log.info("开始migration");SchemaManagementToolCoordinator.process(metadata, registry, settings, null);log.info("开始alter migration");SchemaAlterTool schemaAlterTool = new SchemaAlterTool(registry);schemaAlterTool.performTablesAlter(registry, metadata);}}public void migrateDB(String jdbcUrl, DataSourceProperties dataSource, Set<EntityType<?>> entities, String ddlAuto) {log.info("schema 生成:{}", jdbcUrl);Properties p = new Properties();// 数据库方言,最终输出的方言p.put(AvailableSettings.DIALECT, MySQL5InnoDBDialect.class.getName());// 自动执行的动作p.put(AvailableSettings.HBM2DDL_AUTO, ddlAuto);// 分隔符,默认为空p.put(AvailableSettings.HBM2DDL_DELIMITER, ";");// 是否展示SQLp.put(AvailableSettings.SHOW_SQL, true);p.put("hibernate.connection.driver_class", dataSource.getDriverClassName());p.put("hibernate.connection.url", jdbcUrl);p.put("hibernate.connection.username", dataSource.getUsername());p.put("hibernate.connection.password", dataSource.getPassword());// 是否使用默认的jdbc元数据,默认为true,读取项目自身的元数据p.put("hibernate.temp.use_jdbc_metadata_defaults", true);
//                p.put("hibernate.temp.use_jdbc_metadata_defaults", false);ConfigurationHelper.resolvePlaceHolders(p);try (ServiceRegistry registry = new StandardServiceRegistryBuilder().applySettings(p).build()) {Map settings = registry.getService(ConfigurationService.class).getSettings();MetadataSources metadataSources = new MetadataSources(registry);entities.forEach(entityType -> metadataSources.addAnnotatedClass(entityType.getJavaType()));Metadata metadata = metadataSources.buildMetadata();HashMap properties = new HashMap<>();properties.putAll(registry.getService(ConfigurationService.class).getSettings());log.info("开始migration");SchemaManagementToolCoordinator.process(metadata, registry, settings, null);log.info("开始alter migration");SchemaAlterTool schemaAlterTool = new SchemaAlterTool(registry);schemaAlterTool.performTablesAlter(registry, metadata);}}

自定义 hibernate 的entity 关联 table:

public class SchemaAlterTool {private Logger log = LoggerFactory.getLogger(SchemaAlterTool.class);protected SchemaFilter schemaFilter;ServiceRegistry registry;private HibernateSchemaManagementTool tool;private JdbcContext jdbcContext;public SchemaAlterTool(ServiceRegistry registry) {this.registry = registry;SchemaFilterProvider schemaFilterProvider = registry.getService(StrategySelector.class).resolveDefaultableStrategy(SchemaFilterProvider.class,null,DefaultSchemaFilterProvider.INSTANCE);this.schemaFilter = schemaFilterProvider.getMigrateFilter();}protected void validateColumnType(Table table, Column column, ColumnInformation columnInformation, Metadata metadata, Dialect dialect) {boolean typesMatch = column.getSqlTypeCode(metadata) == columnInformation.getTypeCode() || column.getSqlType(dialect, metadata).toLowerCase(Locale.ROOT).startsWith(columnInformation.getTypeName().toLowerCase(Locale.ROOT));if (!typesMatch) {throw new SchemaManagementException(String.format("Schema-alter: wrong column type encountered in column [%s] in table [%s]; found [%s (Types#%s)], but expecting [%s (Types#%s)]", column.getName(), table.getQualifiedTableName(), columnInformation.getTypeName().toLowerCase(Locale.ROOT), JdbcTypeNameMapper.getTypeName(columnInformation.getTypeCode()), column.getSqlType().toLowerCase(Locale.ROOT), JdbcTypeNameMapper.getTypeName(column.getSqlTypeCode(metadata))));}}/*** @param column            模型信息* @param columnInformation 数据库信息* @return*/protected boolean validateColumnLength(Column column, ColumnInformation columnInformation, Metadata metadata, Dialect dialect) {Value value = column.getValue();String name = value.getType().getName();if (!"string".equals(name)) {return true;}
//        255 默认值忽略if (column.getLength() == 255) {return true;}
//        boolean typesMatch = column.getSqlTypeCode(metadata) == columnInformation.getTypeCode() || column.getSqlType(dialect, metadata).toLowerCase(Locale.ROOT).startsWith(columnInformation.getTypeName().toLowerCase(Locale.ROOT));
//        if (!typesMatch) {
//            return true;
//        }if (column.getSqlType(dialect, metadata).toLowerCase(Locale.ROOT).startsWith("clob")) {return true;}
//        columnInformation.getTypeName()
//        有大佬定义 columnDefinationString sqlType = column.getSqlType();if (!StringUtils.isEmpty(sqlType) && sqlType.length() > 24) {return true;}if (!(column.getLength() == columnInformation.getColumnSize())) {log.info("column {} not match length {}", column.getName(), column.getLength());return false;}return true;}public NameSpaceTablesInformation performTablesAlter(ServiceRegistry registry, Metadata metadata) {tool = (HibernateSchemaManagementTool) registry.getService(SchemaManagementTool.class);Map configurationValues = registry.getService(ConfigurationService.class).getSettings();ExecutionOptions options = new ExecutionOptions() {@Overridepublic boolean shouldManageNamespaces() {return true;}@Overridepublic Map getConfigurationValues() {return configurationValues;}@Overridepublic ExceptionHandler getExceptionHandler() {return ExceptionHandlerLoggedImpl.INSTANCE;}};NameSpaceTablesInformation tablesInformation = new NameSpaceTablesInformation(metadata.getDatabase().getJdbcEnvironment().getIdentifierHelper());jdbcContext = tool.resolveJdbcContext(options.getConfigurationValues());final DdlTransactionIsolator isolator = tool.getDdlTransactionIsolator(jdbcContext);final DatabaseInformation databaseInformation = Helper.buildDatabaseInformation(tool.getServiceRegistry(),isolator,metadata.getDatabase().getDefaultNamespace().getName());try {for (Namespace namespace : metadata.getDatabase().getNamespaces()) {if (schemaFilter.includeNamespace(namespace)) {alterTables(metadata, databaseInformation, options, jdbcContext.getDialect(), namespace);}}} finally {try {databaseInformation.cleanup();} catch (Exception e) {log.debug("Problem releasing DatabaseInformation : " + e.getMessage());}isolator.release();}return tablesInformation;}protected void alterTables(Metadata metadata, DatabaseInformation databaseInformation, ExecutionOptions options, Dialect dialect, Namespace namespace) {NameSpaceTablesInformation tables = databaseInformation.getTablesInformation(namespace);Iterator tableIter = namespace.getTables().iterator();while (tableIter.hasNext()) {Table table = (Table) tableIter.next();if (this.schemaFilter.includeTable(table) && table.isPhysicalTable()) {this.alterTable(table, tables.getTableInformation(table), metadata, options, dialect);}}}protected void alterTable(Table table, TableInformation tableInformation, Metadata metadata, ExecutionOptions options, Dialect dialect) {if (tableInformation == null) {throw new SchemaManagementException(String.format("Schema-alter: missing table [%s]", table.getQualifiedTableName().toString()));} else {Iterator selectableItr = table.getColumnIterator();while (selectableItr.hasNext()) {Selectable selectable = (Selectable) selectableItr.next();if (Column.class.isInstance(selectable)) {Column column = (Column) selectable;ColumnInformation existingColumn = tableInformation.getColumn(Identifier.toIdentifier(column.getQuotedName()));if (existingColumn == null) {throw new SchemaManagementException(String.format("Schema-alter: missing column [%s] in table [%s]", column.getName(), table.getQualifiedTableName()));}
//                    this.validateColumnType(table, column, existingColumn, metadata, dialect);if (!validateColumnLength(column, existingColumn, metadata, dialect)) {log.info("table alter:{}", table.getQualifiedTableName());boolean format = Helper.interpretFormattingEnabled(options.getConfigurationValues());Formatter formatter = format ? FormatStyle.DDL.getFormatter() : FormatStyle.NONE.getFormatter();final GenerationTarget[] targets = new GenerationTarget[]{new GenerationTargetToDatabase(tool.getDdlTransactionIsolator(jdbcContext), true)};migrateTable(table, column, tableInformation, dialect, metadata, formatter, options, targets);}}}}}protected void migrateTable(Table table, Column column, TableInformation tableInformation, Dialect dialect, Metadata metadata, Formatter formatter, ExecutionOptions options, GenerationTarget... targets) {Database database = metadata.getDatabase();AlterTable alterTable = new AlterTable(table);applySqlStrings(false, alterTable.sqlAlterStrings(dialect, metadata, tableInformation,column,database.getDefaultNamespace().getPhysicalName().getCatalog(),database.getDefaultNamespace().getPhysicalName().getSchema()),formatter,options,targets);for (int i = 0; i < targets.length; i++) {targets[i].release();}}void applySqlStrings(boolean quiet, Iterator sqlStrings, Formatter formatter, ExecutionOptions options, GenerationTarget... targets) {if (sqlStrings != null) {while (sqlStrings.hasNext()) {String sqlString = (String) sqlStrings.next();applySqlString(quiet, sqlString, formatter, options, targets);}}}private static void applySqlString(boolean quiet, String sqlString, Formatter formatter, ExecutionOptions options, GenerationTarget... targets) {if (!StringHelper.isEmpty(sqlString)) {String sqlStringFormatted = formatter.format(sqlString);GenerationTarget[] exeProcessor = targets;int excCount = targets.length;for (int i = 0; i < excCount; ++i) {GenerationTarget target = exeProcessor[i];try {target.accept(sqlStringFormatted);} catch (CommandAcceptanceException var11) {if (!quiet) {options.getExceptionHandler().handleException(var11);}}}}}
}

相关文章:

编程修炼之Hibernate--- springboot启动初始化ddl过程与如何自定义修改 table 字段长度

文章目录 springboot启动初始化ddl过程如何自定义修改 table springboot启动初始化ddl过程 跟踪Springboot整合hibernate的启动代码&#xff1a; SessionFactoryImpl 的初始化里做了非常多的事情&#xff0c;初始化各种资源&#xff0c;并调用 SchemaManagementToolCoordinat…...

TOMCAT入门到精通

目录 一 WEB技术 1.1 HTTP协议和B/S 结构 1.2 前端三大核心技术 1.2.1 HTML 1.2.2 CSS&#xff08;Cascading Style Sheets&#xff09;层叠样式表 1.2.3 JavaScript 二 WEB框架 2.2后台应用架构 2.2.1单体架构 2.2.2微服务 2.2.3单体架构和微服务比较 三 tomcat的…...

Android笔试面试题AI答之Kotlin(18)

文章目录 86. 阐述Kotlin中性能优化之局部函数 &#xff1f;局部函数的优点间接的性能优化注意事项 87. 简述Kotlin中性能优化之数组使用 &#xff1f;1. 选择合适的数组类型2. 避免不必要的数组创建3. 优化数组访问4. 合理使用数组遍历方式5. 利用Kotlin的集合操作API6. 注意数…...

Linux基础知识学习(五)

1. 用户组管理 每个用户都有一个用户组&#xff0c;系统可以对一个用户组中的所有用户进行集中管理&#xff08;开发、测试、运维、root&#xff09;。不同Linux 系统对用户组的规定有所不同&#xff0c;如Linux下的用户属于与它同名的用户组&#xff0c;这个用户组在创建用户…...

股票买卖的思路与代码

题目 1302&#xff1a;股票买卖 时间限制: 1000 ms 内存限制: 65536 KB 提交数:8660 通过数: 4290 【题目描述】 最近越来越多的人都投身股市&#xff0c;阿福也有点心动了。谨记着“股市有风险&#xff0c;入市需谨慎”&#xff0c;阿福决定先来研究一下简化版的股…...

Eureka Server与Eureka Client详解:服务注册与发现的交互机制

Eureka Server与Eureka Client详解&#xff1a;服务注册与发现的交互机制 Eureka 是 Netflix 开源的一个服务发现框架&#xff0c;它是 Spring Cloud 微服务架构中的核心组件之一。Eureka 主要由两个关键组件构成&#xff1a;Eureka Server 和 Eureka Client。它们之间通过一定…...

php-fpm 如何查看哪个正在执行死循环 并终止

php-fpm 如何查看哪个正在执行死循环 并终止 1. 检查 PHP-FPM 进程的 CPU 使用情况 首先&#xff0c;使用 top 或 htop 命令检查哪个 PHP-FPM 进程占用了大量的 CPU 资源。这个进程很可能是在死循环中。 top -c在 top 命令输出中&#xff0c;按 P 键可以按 CPU 使用率排序。…...

电脑硬盘坏了怎么恢复数据?

在数字化时代&#xff0c;电脑硬盘作为存储核心&#xff0c;承载着我们的工作文档、学习资料、家庭照片以及无数珍贵的回忆。然而&#xff0c;硬盘作为机械设备&#xff0c;也有其寿命和脆弱性&#xff0c;一旦出现故障&#xff0c;数据恢复便成为了一个紧迫而棘手的问题。本文…...

cdga|某大型企业数据治理的成功转型:构建数据驱动的竞争力新引擎

在当今这个数据爆炸的时代&#xff0c;数据已成为企业最宝贵的资产之一&#xff0c;其有效管理和利用直接关系到企业的核心竞争力。某大型企业&#xff0c;作为行业内的领军企业&#xff0c;面对海量数据带来的机遇与挑战&#xff0c;果断启动了一项全面而深入的数据治理项目&a…...

C#使用 ModeBusTCP读取汇川Easy521PLC

Modbus TCP是一种基于以太网TCP/IP的Modbus协议变种&#xff0c;它允许Modbus协议在以太网网络上运行&#xff0c;使得设备之间可以通过IP网络交换数据。Modbus由MODICON公司于1979年开发&#xff0c;是一种工业现场总线协议标准&#xff0c;广泛应用于工业自动化领域。 #regio…...

PostgreSQL的postgres主进程

PostgreSQL的postgres主进程 在PostgreSQL数据库系统中&#xff0c;主要的后台进程各司其职&#xff0c;保证数据库的高效运行。其中&#xff0c;主进程postgres&#xff08;也称为Postmaster&#xff09;是整个数据库的核心&#xff0c;它负责管理和协调所有其他后台进程&…...

Java实现K个排序链表的高效合并:逐一合并、分治法与优先队列详解

Java实现K个排序链表的高效合并&#xff1a;逐一合并、分治法与优先队列详解 在算法和数据结构的学习中&#xff0c;链表是一个非常基础但又极具挑战的数据结构。尤其是当面对合并多个排序链表的问题时&#xff0c;如何在保证效率的前提下实现代码的简洁与高效&#xff0c;往往…...

Xinstall揭秘:高效App推广背后的黑科技

在移动互联网时代&#xff0c;App的运营推广成为了开发者们最为关注的话题之一。然而&#xff0c;随着市场竞争的加剧&#xff0c;推广难度也越来越大。这时候&#xff0c;一款名为Xinstall的品牌走进了我们的视线&#xff0c;它以其独特的技术和解决方案&#xff0c;为App推广…...

星巴克VS瑞幸,新王、旧王之争给新CEO带来哪些启示

“变化是生命的元素&#xff0c;求变是生命的力量”&#xff0c;马克吐温曾这样解释生命。而商场上何尝不是如此&#xff0c;正因为世异则事异&#xff0c;求变也是企业的常态。 近日&#xff0c;星巴克官宣布莱恩尼科尔(Brian Niccol)将于9月9日接替拉什曼纳拉辛汉(Laxman Na…...

C语言 | Leetcode C语言题解之第354题俄罗斯套娃信封问题

题目&#xff1a; 题解&#xff1a; int cmp(int** a, int** b) {return (*a)[0] (*b)[0] ? (*b)[1] - (*a)[1] : (*a)[0] - (*b)[0]; }int maxEnvelopes(int** envelopes, int envelopesSize, int* envelopesColSize) {if (envelopesSize 0) {return 0;}qsort(envelopes, …...

大型俄罗斯国际展览会介绍

今天分享一些在俄罗斯比较知名的国际展览会&#xff0c;以下展会大多为一年一届&#xff0c;具体展出时间大家可去网上查询了解&#xff0c;充分利用合适的展会&#xff0c;无疑是企业拓展市场、塑造品牌、对接资源、紧跟行业趋势的重要途径。 1、俄罗斯国际食品展览会 展览地…...

CST软件仿真案例:圆极化平板天线仿真02

本期继续完成一款圆极化Patch天线的仿真实例。读者可以完整的了解到怎么用CST微波工作室&#xff0c;完成对一款天线建模、设置到仿真分析的完整过程。 本期中&#xff0c;我们要设计的圆极化天线尺寸如下图所示&#xff1a; 本期内容是接着上期部分开始。首先先完成仿真实例0…...

【前端】vue监视属性和计算属性对比

首先分开讲解各个属性的作用。 1.计算属性 作用&#xff1a;用来计算出来一个值&#xff0c;这个值调用的时候不需要加括号&#xff0c;会根据依赖进行缓存&#xff0c;依赖不变&#xff0c;computed的值不会重新计算。 const vm new Vue({el:#root,data:{lastName:张,firstNa…...

探索提示工程 Prompt Engineering的奥妙

一、探索提示工程 Prompt Engineering 1. 介绍通用人工智能和专用人工智能 人工智能&#xff08;AI&#xff09;可以分为通用人工智能&#xff08;AGI&#xff09;和专用人工智能&#xff08;Narrow AI&#xff09;。AGI是一种能够理解、学习和执行任何人类可以完成的任务的智…...

算法阶段总结1

阶段总结 通过今天晚上的这场div2我深刻的意识到&#xff0c;光是会找窍门是远远不够的&#xff0c;你得会基础的建图&#xff0c;dp&#xff0c;高级数据结构&#xff0c;你这样才可以不断的提升自己&#xff0c;不可以一直在一个阶段停留下去&#xff0c;构造题可以刷下去&a…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

【WiFi帧结构】

文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成&#xff1a;MAC头部frame bodyFCS&#xff0c;其中MAC是固定格式的&#xff0c;frame body是可变长度。 MAC头部有frame control&#xff0c;duration&#xff0c;address1&#xff0c;address2&#xff0c;addre…...

大数据零基础学习day1之环境准备和大数据初步理解

学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 &#xff08;1&#xff09;设置网关 打开VMware虚拟机&#xff0c;点击编辑…...

连锁超市冷库节能解决方案:如何实现超市降本增效

在连锁超市冷库运营中&#xff0c;高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术&#xff0c;实现年省电费15%-60%&#xff0c;且不改动原有装备、安装快捷、…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

华为OD最新机试真题-数组组成的最小数字-OD统一考试(B卷)

题目描述 给定一个整型数组,请从该数组中选择3个元素 组成最小数字并输出 (如果数组长度小于3,则选择数组中所有元素来组成最小数字)。 输入描述 行用半角逗号分割的字符串记录的整型数组,0<数组长度<= 100,0<整数的取值范围<= 10000。 输出描述 由3个元素组成…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...

WebRTC调研

WebRTC是什么&#xff0c;为什么&#xff0c;如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...