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

框架源码私享笔记(02)Mybatis核心框架原理 | 一条SQL透析核心组件功能特性

最近在思考一个问题:如何能够更好的分享主流框架源码学习笔记(主要是源码部分)?让有缘刷到的同学既可以有所收获,还能保持对相关技术架构探讨学习热情和兴趣。以及自己也保持较高的分享热情和动力。

今天尝试用一个SQL查询作为引子,去解构Mybatis的核心原理和关键源码处理流程。这种更加贴合工作实践方式,相信可以降低探索核心源码门槛。


一、前言背景

二、Mybatis概述

三、Mybatis的核心原理

3.1 Mybatis核心功能处理流程

3.1.1 解析配置-加载并解析Mapper配置文件

3.1.2 创建连接-创建SqlSessionFactory并获取sqlSession连接

3.1.3 执行SQL语句-Executor

3.1.4 结果数据封装 MapperStatement & ResultSetHandler

3.1.5 关闭连接

四、核心功能特性

4.1 支持动态灵活的SQL

4.2 详解一级、二级缓存机制

4.2.1 二级缓存为什么默认不开启?

4.3 支持插件扩展

4.4 延迟加载

4.5 SQL注解


【公众号搜索:拉丁解牛说技术】欢迎一起交流讨论。

一、前言背景

在10多年前,那时候刚开始工作,移动互联网还没发展起来,Mybatis还没流行,后端应用开发,主流用的是SSH框架。回想那时候的Hibernate、Spring,配置多又杂,其实对新手并不友好。然而相比手写JDBC连接管理、繁琐的结果数据转换,让SSH当年也是火了好几年。

随着Hibernate和Mybatis的不断发展,研发人员成功解放手写JDBC数据库连接查询相关研发工作。他们都是优秀的ORM对象关系映射管理框架,也就是持久层框架。但是Hibernate存在对复杂sql关系支持弱、不支持存储过程、性能差、调优难、全表映射复杂等问题,用的人越来越少。

而后起之秀Mybatis,当今最经典ORM框架,由于其灵活易用、好扩展、支持复杂SQL、出色的性能,较好的平衡对象关系映射管理和SQL编写支持,称为半ORM框架,已经成功替代Hibernate。

今天我们梳理Mybatis的核心原理和工作流程,以及重点分析它的一些核心功能特性。

二、Mybatis概述

Mybatis是一个持久层框架,具体就是用来操作数据库数据,并转换成目标对象的技术框架。它的核心在于将表数据和对象实例进行关联映射,也就是ORM(object relation Mapping)。

Mybatis之所以可以替换Hibernate,主要是支持SQL定制、高级的映射管理功能、缓存机制、还有存储过程(由于大数据技术发展,目前存储过程用的人也越来越少,但是在那个年代支持存储过程非常实用)。Mybatis灵活可扩展高性能的特性,让我们开发读写数据,几乎不需要编程,主要做的工作就是编写Mapper配置文件,把SQL和对象关系映射管理好,就可以实现CRUD。而多类型数据库的切换迁移,对系统应用来说,简单到只需要替换JDBC的驱动。

三、Mybatis的核心原理

如上所述,Mybatis核心工作就是帮助研发人员对数据库的读写操作,简化成面向对象操作。

对于一个完全不懂Mybatis或者ORM的人来说,如果要实现读写数据库,该怎么实现?这个相信很多人都能回答:通过jdbc连接数据库、执行SQL、解析sql数据结果,就三个步骤完成。

而Mybatis的核心原理逻辑更加细化,但整体也是类似以上三个步骤。毕竟大家目标一致,只是实现过程不同而已。

接下来我们用一个非常简单的demo,就是通过Mybatis去读数据库数据,demo就只有几行代码,然后循序渐进了解Mybatis的核心工作原理,以及核心源码组件功能。


package com.lading.mybaties;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;
import java.io.InputStream;public class MyBatisDemo {public static void main(String[] args) throws IOException {InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);try (SqlSession sqlSession = sqlSessionFactory.openSession()) {sqlSession.selectOne("com.lading.mapper.UserMapper.getUserById", 1);}}
}

3.1 Mybatis核心功能处理流程

Mybatis整体框架,基于面向对象思想去实现与数据库表数据交互,它的核心步骤按顺序处理有以下五个。

3.1.1 解析配置-加载并解析Mapper配置文件

Mybatis通过SqlSessionFactoryBuilder来加载解析配置文件,并生SqlSessionFactory。

SqlSessionFactoryBuilder是Mybatis的入口类,类似tomcat的org.apache.catalina.startup.Bootstrap 启动类。

比如我们项目只有Mybatis包、jdbc驱动,想要基于Mybatis去读写数据,首先需要通过以下三行代码去解析你的Mybatis相关配置文件,以及构建一个SqlSessionFactory,为后续创建数据库连接和读写做准备。

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

这三行代码里最后一行,看源码会发现,里面做了非常多的工作,细无巨细的把Mybatis管理配置文件、还有对象sql映射Mapper文件一一解析,包括properties、settings、environment、mapper等标签数据,以及业务相关的mapper文件里的resultMap、CURD 标签都会转成configration对象属性。

最后利用解析结果数据存放的对象configration去实例化构建sql 会话工厂:

new DefaultSqlSessionFactory(config)。

3.1.2 创建连接-创建SqlSessionFactory并获取sqlSession连接

解析完成配置文件后,Mybatis框架已经清晰知道Mybatis的基础配置信息、连接数据库的类型、用户密码信息,还有相关表映射关系。

通过SqlSessionFactoryBuilder构建了session工厂实例SqlSessionFactory,看名字可以知道是通过建造者模式去实例化该对象。

SqlSessionFactory是Mybatis的核心接口,它就是用来负责实现管理会话连接。

在应用启动或者需要用到Mybatis读写数据时候,就生成一个实例DefaultSqlSessionFactory(它是session工厂接口唯一实现类)。

SqlSessionFactory,通常在应用里是全局唯一并共享。

然后通过会话工厂实例sqlSessionFactory去开启一个session连接:

SqlSession sqlSession = sqlSessionFactory.openSession();

SqlSession就是真正负责执行sql、并且管理事务的核心功能类,它底层是jdbc的连接。

session每次用完就关闭,需要用的时候再次新建。但是Mybatis也有实现对应的连接池,如果配置了连接池就不会关闭。 Mybatis的连接池,后面出一篇文章专门分享Mybatis如何管理连接池。

比如,通过session去查询用户ID=1的用户数据:

SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User ladingUser = userMapper.selectUserById(1);
System.out.println(ladingUser);
3.1.3 执行SQL语句-Executor

在3.1.2里,看起来sql session执行了sql查询,但是DefaultSqlSession里面封装了一个Executor执行器。

Executor执行器,它是真正负责执行sql的打工人,里面有一个抽象类BaseExecutor,通过模板方法模式去共享自己的模板方法能力。另外三个子类去继承实现不同的db操作。

这三个执行器的主要区别在于:

SimpleExecutor,是一个最简单的执行器,每次执行sql都新建一个Statement对象。

比如它里面的query方法源码:

@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, 
RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {// JDBC中 Statement接口Statement stmt = null;try {// 获取到Configuration对象Configuration configuration = ms.getConfiguration();StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);// 里面创建Connection代理对象,新增这个Statementstmt = prepareStatement(handler, ms.getStatementLog());// 执行查询,封装结果集return handler.query(stmt, resultHandler);} finally {closeStatement(stmt);}
}

ReuseExecutor,顾名思义是可复用执行器。特点是,复用预处器PreparedStatement。

比如获取预处理Statement的方法源码:

而BatchExcutor,叫做批量执行器,支持批量处理SQL语句。

3.1.4 结果数据封装 MapperStatement & ResultSetHandler

结果数据封装逻辑里面相对繁琐。实际上在Excutor执行sql之前,也依赖mapperStatement去封装sql语句、sql的入参。底层通过jdbc connection执行sql后,通过ResultSetHandler和TypeHandler去解析封装结果数据。

3.1.5 关闭连接

最后是关闭sqlsession,释放资源。如果是配置应用连接池,就是归还连接操作。

四、核心功能特性

4.1 支持动态灵活的SQL

直接允许在mapper xml文件配置动态的sql。包括if、where、choose、when、foreach等多种动态条件。这个能力让Mybatis成功支持复杂关联sql处理。

4.2 详解一级、二级缓存机制

Mybatis支持缓存,大幅提升数据库查询性能。默认开启一级缓存,关闭二级缓存。

一级缓存:是基于sqlsession去实现,同一个sql session多次查询,会复用相同sql 的缓存结果。底层是通过把一个SQL的id、名称、入参计算得到一个唯一key,并和结果数据存入一个map里。

当同一个sql session后面重复的查询,就会判断缓存是否有数据,如果有就直接返回,不再继续从数据库里查询数据,大幅提升单个sql session里的重复查询效率。

如果在一个sql session里出现了update、delete、insert、或者commit、close session操作,就会自动去清空缓存,确保没有脏数据在Mybatis一级缓存里。

该缓存默认开启。如果要关闭,可以通过flushCache=true去关闭。

二级缓存:是基于mapper,也就是命名空间级别的缓存。相当于sqlSessionFactory级别,比一级缓存sqlSession更高一个层级。在同一个mapper下,所有session会话产生的缓存数据统一在mapper里命名空间管理。多个mapper的二级缓存互不干扰。

二级缓存,默认是关闭的。可以在mapper里,新增cache标签就可以开启。

<mapper namespace="com.lading.mapper.UserMapper">
<!--启用二级缓存-->
<cache eviction="FIFO" flushInterval="30000" readOnly="true"/>
</mapper>

4.2.1 二级缓存为什么默认不开启?

之所以默认关闭,主要因为二级缓存可能有脏读。

正因为所有session会话产生的缓存数据,统一在mapper里命名空间管理,多个mapper的二级缓存互不干扰。这里就可能导致研发人员如果在另一个mapper新增或者修改了数据,其他地方mapper缓存的数据就没有被自动更新,就会造成生产故障。

当然这个Mybatis有提供相关配置,支持关联mapper同步被动去清空二级缓存,避免干扰。

4.3 支持插件扩展

Mybatis允许研发人员在核心组件中插入自定义的逻辑,比如分页、拦截器、性能监控插件功能 。

插件的开发,可以通过实现 org.apache.ibatis.pluginInterceptor接口,然后实现里面 intercept、plugin 和 setProperties方法来新增插件功能。

比如增加一个执行sql监控功能。

package com.lading.mybaties;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;import java.util.Properties;public class TimeMonitorPlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {long startTime = System.currentTimeMillis();Object result = invocation.proceed(); // 执行目标方法long endTime = System.currentTimeMillis();System.out.println("SQL 执行耗时: " + (endTime - startTime) + "ms");return result;}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 可以设置拦截器的属性}
}

在 mybatis-config.xml 文件中注册自定义拦截器:

<plugins>
<plugin interceptor="lading.mybaties.TimeMonitorPlugin"/>
</plugins>

sql查询的时候就会打印sql执行时间。

4.4 延迟加载

可以控制关联对象,在需要用到的时候才去加载。比如1-n的场景,一个学生有多门课程信息。查询一个学生基本信息的时候,如果没有用到课程列表,就不需要在关联查询里把课程列表页拉出去,提升了查询效率。

//fetchType=lazy开启延迟加载
<association property="xxx" fetchType="lazy">

这个延迟加载功能,和Springboot通过@lazy注解去解决循环依赖问题,有类似异曲同工的作用。

4.5 SQL注解

MyBatis 也支持使用注解来配置 SQL 映射,从而简化 XML 配置,可以实现零xml配置文件去操作数据库数据。常用的注解包括常规的CURD:

@Select

@Insert

@Update

@Delete

还有,@Results结果映射注解。

比如通过名称去查询用户:

@Select("SELECT * FROM user WHERE name = #{name}")
@Results({@Result(property = "id", column = "id"),@Result(property = "name", column = "name")
})
User selectUserByName(String name);

相关文章:

框架源码私享笔记(02)Mybatis核心框架原理 | 一条SQL透析核心组件功能特性

最近在思考一个问题&#xff1a;如何能够更好的分享主流框架源码学习笔记&#xff08;主要是源码部分&#xff09;?让有缘刷到的同学既可以有所收获&#xff0c;还能保持对相关技术架构探讨学习热情和兴趣。以及自己也保持较高的分享热情和动力。 今天尝试用一个SQL查询作为引…...

如何重置 MySQL root 用户的登录密码?

重置 MySQL root 密码的核心步骤是绕过权限验证登录数据库并更新密码字段。以下是具体方法&#xff1a; 方法一&#xff1a;通过 --SKIP-GRANT-TABLES 模式修改密码 停止 MySQL 服务 Windows&#xff1a;在命令行执行 net stop mysql&#xff08;服务名可能为 mysql80 或 mysql…...

ArrayList底层结构和源码分析笔记

参考视频&#xff1a;韩顺平Java集合 ArrayList特点 ArrayList 可以加入 null&#xff0c;包括多个。 ArrayList 是由数组来实现数据存储的 ArrayList 基本等同于 Vector&#xff0c;除了 ArrayList 是线程不安全&#xff08;执行效率高&#xff09;。在多线程情况下&#xf…...

Centos离线安装gcc

文章目录 Centos离线安装gcc1. gcc是什么&#xff1f;2. gcc下载地址3. gcc的安装4. 安装结果验证 Centos离线安装gcc 1. gcc是什么&#xff1f; GCC&#xff08;GNU Compiler Collection&#xff09;是 GNU 项目下的开源编译器套件&#xff0c;主要用于将 C、C 等编程语言的源…...

flutter 图片资源路径管理

1. 创建统一资源管理类 创建一个单独的 Dart 文件&#xff08;比如 manager.dart&#xff09;&#xff0c;将所有图片路径集中管理。这样在引用图片时&#xff0c;不需要每次都手动输入完整路径&#xff0c;只需通过常量引用即可。 //manager.dartclass Manager { static co…...

[内网渗透] 红日靶场2

环境配置 靶场地址: http://vulnstack.qiyuanxuetang.net/vuln/wiki/ 环境配置可以看这个: https://www.bilibili.com/video/BV1De4y1a7Ps/?spm_id_from333.337.search-card.all.click&vd_sourcecf73ac8de9b7c0322b1bccf77de91c5dNAT模式分配111段, DHCP也要更改 再添加…...

【cocos creator】游戏优化,内存,性能,包体积大小,加载,drawcall优化

参考&#xff1a; https://blog.csdn.net/qq_47012987/article/details/140169024 内存泄露排查 使用chrome测试cocos creator内存泄漏问题手游内存优化cocos creator优化Creator资源自动释放逻辑&#xff1a;所有 cc.Asset 实例都拥有成员函数 addRef 和 decRef&#xff0c;分…...

MySQL 企业版 TDE加密后 测试和问题汇总

一、测试keyring file 1.1 当keyring file文件丢失或者被篡改 结论&#xff1a;不影响当前正在运行的数据库&#xff0c;但是在重启服务后会启动失败出现报错。 tail -n 100 /var/log/mysql/error.log 报错信息如下&#xff1a; 2025-03-12T08:04:54.668847Z 1 [ERROR] [M…...

Unity 封装一个依赖于MonoBehaviour的计时器(下) 链式调用

[Unity] 封装一个依赖于MonoBehaviour的计时器(上)-CSDN博客 目录 1.加入等待间隔时间"永远执行方法 2.修改为支持链式调用 实现链式调用 管理"链式"调度顺序 3.测试 即时方法​编辑 "永久"方法 链式调用 ​4.总结 1.加入等待间隔时间&qu…...

petalinux环境下给linux-xlnx源码打补丁

在调试88e1512芯片时官方驱动无法满足我的应用方式&#xff0c;因此修改了marvell.c源码&#xff0c;但是在做bsp包重新创建新工程时发现之前的修改没有生效&#xff0c;因此查找了一下资料发现可以通过打补丁的方式添加到工程文件中&#xff0c;便于管理。 操作步骤 一、获取…...

套接字缓冲区以及Net_device

基础网络模型图 一般网络设计分为三层架构和五层设计&#xff1a; 一、三层架构 用户空间的应用层 位于最上层&#xff0c;是用户直接使用的网络应用程序&#xff0c;如浏览器、邮件客户端、即时通讯软件等。这些程序通过系统调用&#xff08;如 socket 接口&#xff09;向内核…...

2024下半年真题 系统架构设计师 案例分析

案例一 软件架构 关于人工智能系统的需求分析&#xff0c;给出十几个需求。 a.系统发生业务故障时&#xff0c;3秒内启动 XXX&#xff0c;属于可靠性 b.系统中的数据进行导出&#xff0c;要求在3秒内完成&#xff0c;属于可用性 c.质量属性描述&#xff0c;XXX&#xff0c;属…...

AI学习——深度学习核心技术深度解析

一、深度学习的本质与核心思想 定义&#xff1a;通过多层非线性变换&#xff0c;自动学习数据层次化表征的机器学习方法 核心突破&#xff1a; ​表征学习&#xff1a;自动发现数据的内在规律&#xff0c;无需人工设计特征​端到端学习&#xff1a;直接从原始输入到最终输出&…...

c++介绍智能指针 十二(2)

智能指针share_ptr,与unique_ptr不同&#xff0c;多个shar_ptr对象可以共同管理一个指针&#xff0c;它们通过一个共同的引用计数器来管理指针。当一个智能指针对象销毁时&#xff0c;计数器减一。当计数器为0时&#xff0c;会将所指向的内存对象释放。 #include<memory>…...

西门子S7-1200 PLC远程调试技术方案(巨控GRM532模块)

三步快速实现远程调试 硬件部署 准备西门子S7-1200 PLC、巨控GRM552YW-C模块及编程电脑。GRM552YW-C通过网口与PLC连接&#xff0c;支持4G/5G/Wi-Fi/有线网络接入&#xff0c;无需复杂布线。 软件配置 安装GVCOM3配置软件&#xff0c;注册模块&#xff08;输入唯一序列号与密…...

vue启动 localhost无法访问

1. localhost 和 127.0.0.1 虽然都指向本机&#xff0c;但它们有细微的区别&#xff1a; - localhost 是一个域名&#xff0c;需要通过 DNS 解析或本地 hosts 文件解析为 IP 地址 - 127.0.0.1 是直接的 IP 地址&#xff0c;不需要解析过程 2. 无法访问 localhost 的可…...

Mac上更改默认应用程序

Mac上为某些文件设置默认打开应用的时候&#xff0c;刚开始是通过打开方式&#xff0c;其他里面&#xff0c;勾选始终以此方式打开&#xff0c;但实际上这个功能并不太好用&#xff0c;经常会让人误以为已经设置好了。但是实际上只是在当前目录起作用。真正解决这个问题可以按照…...

【开源+代码解读】Search-R1:基于强化学习的检索增强大语言模型框架3小时即可打造个人AI-search

大语言模型(LLMs)在处理复杂推理和实时信息检索时面临两大挑战:知识局限性(无法获取最新外部知识)和检索灵活性不足(传统方法依赖固定检索流程)。现有方法如检索增强生成(RAG)和工具调用(Tool-Use)存在以下问题: RAG:单轮检索导致上下文不足,无法适应多轮交互场景…...

贪心算法和遗传算法优劣对比——c#

项目背景&#xff1a;某钢管厂的钢筋原材料为 55米&#xff0c;工作需要需切割 40 米&#xff08;1段&#xff09;、11 米&#xff08;15 段&#xff09;等 4 种规格 &#xff0c;现用贪心算法和遗传算法两种算法进行计算&#xff1a; 第一局&#xff1a;{ 40, 1 }, { 11, 15…...

网络安全防护总体架构 网络安全防护工作机制

1 实践内容 1.1 安全防范 为了保障"信息安全金三角"的CIA属性、即机密性、完整性、可用性&#xff0c;信息安全领域提出了一系列安全模型。其中动态可适应网络安全模型基于闭环控制理论&#xff0c;典型的有PDR和P^2DR模型。 1.1.1 PDR模型 信息系统的防御机制能…...

SpringCloud带你走进微服务的世界

认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 单体架构 单体架构&#xff1a;将业务的所有功能集中在一个项目中开发&#xff0c;打成一个包部…...

Python设计模式 - 建造者模式

定义 建造者模式是一种创建型设计模式&#xff0c;主要用于构建包含多个组成部分的复杂对象。它将对象的构建过程与表示分离&#xff0c;使得同样的构建过程可以创建不同的对象表示。 结构 抽象建造者&#xff08;Builder&#xff09;&#xff1a;声明创建产品的各个部件的方…...

在 Ubuntu 上安装和配置 Docker 的完整指南

Docker 是一个开源的平台&#xff0c;旨在简化应用程序的开发、部署和运行。通过将应用程序及其依赖项打包到容器中&#xff0c;Docker 确保应用程序可以在任何环境中一致地运行。 目录 前言安装前的准备安装 Docker 步骤 1&#xff1a;更新包索引步骤 2&#xff1a;安装必要…...

网络安全之数据加密(DES、AES、RSA、MD5)

刚到公司时&#xff0c;我的工作就是为app端提供相应的接口。之前app使用的是PHP接口&#xff0c;对数据加密方面做得比较少。到使用java接口时&#xff0c;老大开始让我们使用DES加密&#xff0c;进行数据传输&#xff0c;但是后来觉得DES是对称加密&#xff0c;密钥存在客户端…...

基于SpringBoot的“校园周边美食探索及分享平台”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“校园周边美食探索及分享平台”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 校园周边美食探索及分享平台结构图…...

vscode关闭仓库后如何打开

vscode源代码管理->更改->代码 关闭仓库后如何打开。 关闭仓库操作 打开仓库操作 1.按下 Ctrl Shift P&#xff08;Windows/Linux&#xff09;或 Cmd Shift P&#xff08;Mac&#xff09;打开命令面板。 2.在命令面板中输入 Git: Open Repository&#xff0c;然后选…...

Node.js Web 模块详解

Node.js Web 模块详解 引言 Node.js作为一款流行的JavaScript运行环境&#xff0c;以其高性能、事件驱动和非阻塞I/O模型而闻名。在Node.js中&#xff0c;模块是构建应用程序的基础&#xff0c;也是其强大的关键所在。本文将详细介绍Node.js的Web模块&#xff0c;包括其基本概…...

DeepSeek-R1 论文阅读总结

1. QA问答&#xff08;我的笔记&#xff09; Q1: DeepSeek如何处理可读性问题&#xff1f; 通过构建冷启动数据&#xff08;数千条长CoT数据&#xff09;微调基础模型&#xff0c;结合多阶段训练流程&#xff08;RL训练、拒绝采样生成SFT数据&#xff09;&#xff0c;并优化输…...

scoop退回软件版本的方法

title: scoop退回软件版本的方法 date: 2025-3-11 23:53:00 tags: 其他 前言 在软件更新后&#xff0c;如果出现了很影响使用体验的问题&#xff0c;那么可以把软件先退回以前的版本进行使用&#xff0c; 但是scoop本身并没有提供直接让软件回退版本的功能&#xff0c;因此…...

Linux 》》Ubuntu 18 LTS 之后的版本 修改IP地址 主机名

进入目录 /etc/netplan 修改 50-cloud-init.yaml 》保存文件后&#xff0c;执行以下命令应用更改&#xff1a; sudo netplan apply 》》 DHCP模式 修改主机名 hostnamectl set-hostname xxxx 修改cloud.cfg 防止重启主机名还原 但测试下来 不修改&#xff0c; 重启 也不会还…...