Mybatis快速入门与核心知识总结
Mybatis
- 1. 实体类(Entity Class)
- 1.1 实体类的定义
- 1.2 简化编写
- 1.2.1 @Data
- 1.2.2 @AllArgsConstructor
- 1.2.3 @NoArgsConstructor
- 2. 创建 Mapper 接口
- 2.1 @Param
- 2.2 #{} 占位符
- 2.3 SQL 预编译
- 3. 配置 MyBatis XML 映射文件(可选)
- 3.1 默认规则
- 4. 配置 MyBatis 主配置文件
- 4.1 Properties配置项解析
- 4.2 Properties 和 YAML/YML 配置文件的对比
- 5. 编写测试代码
- 5.1 @SpringBootTest
- 5.2 @Autowired
- 5.3 userList.forEach(System.out::println)
MyBatis 是一个优秀的持久层框架,它简化了 JDBC 的使用,允许开发者通过 XML 或注解方式配置 SQL 语句,并自动将查询结果映射为 Java 对象,从而高效地进行数据库操作。
1. 实体类(Entity Class)
com/itheima/pojo/User.java
package com.itheima.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {private Integer id;private String username;private String password;private String name;private Integer age;
}
1.1 实体类的定义
实体类(Entity Class)是用于表示数据库中数据结构的对象模型。它们通常包含与数据库表列相对应的属性,并提供相应的getter和setter方法来访问这些属性。此外,实体类还可能包含一些业务逻辑或验证规则。

1.2 简化编写
其中,@Data、@AllArgsConstructor 和 @NoArgsConstructor 是 Lombok 提供的注解,用于简化 Java 类的编写。这些注解可以自动生成常见的代码,减少样板代码(boilerplate code),使代码更加简洁和易读。下面是对这三个注解的简要解释:
1.2.1 @Data
@Data 是 Lombok 提供的一个综合性注解,它实际上是以下多个注解的组合:
@Getter和@Setter: 自动生成所有字段的 getter 和 setter 方法。@ToString: 自动生成toString()方法。@EqualsAndHashCode: 自动生成equals()和hashCode()方法。@RequiredArgsConstructor: 生成一个包含所有final字段或标记为@NonNull的构造函数。
1.2.2 @AllArgsConstructor
@AllArgsConstructor 注解用于生成一个包含所有字段的构造函数。每个字段都会成为构造函数的一个参数。
使用 @AllArgsConstructor 注解后,Lombok 会为 User 类生成如下构造函数:
public User(Integer id, String username, String password, String name, Integer age) {this.id = id;this.username = username;this.password = password;this.name = name;this.age = age;
}
1.2.3 @NoArgsConstructor
@NoArgsConstructor 注解用于生成一个无参构造函数。这对于需要反射创建对象的框架(如 Spring、Hibernate 等)非常有用。
使用 @NoArgsConstructor 注解后,Lombok 会为 User 类生成如下无参构造函数:
public User() {
}
2. 创建 Mapper 接口
创建一个 UserMapper 接口,定义与 User 相关的数据库操作方法。
com/itheima/mapper/UserMapper.java
package com.itheima.mapper;import com.itheima.pojo.User;
import org.apache.ibatis.annotations.*;import java.util.List;@Mapper //应用程序在运行时, 会自动的为该接口创建一个实现类对象(代理对象), 并且会自动将该实现类对象存入IOC容器 - bean
public interface UserMapper {/*** 查询所有用户*/@Select("select id, username, password, name, age from user")public List<User> findAll();/*** 根据ID删除用户*/@Delete("delete from user where id = #{id}")//public void deleteById(Integer id);public Integer deleteById(Integer id);/*** 新增用户*/@Insert("insert into user(username, password, name, age) values (#{username}, #{password}, #{name}, #{age})")public void insert(User user);/*** 更新用户*/@Update("update user set username = #{username}, password = #{password}, name = #{name}, age = #{age} where id = #{id}")public void update(User user);/*** 根据用户名和密码查询用户*/@Select("select * from user where username = #{username} and password = #{password}")public User findByUsernameAndPassword(@Param("username") String username,@Param("password") String password);
}
2.1 @Param
@Param 注解用于给方法参数命名,使得在 SQL 映射文件或注解中可以通过名称引用这些参数。这对于有多个参数的方法特别有用,而且在默认情况下,方法的形参名称不会被保留在 .class 字节码中。这意味着在运行时,MyBatis 无法直接获取方法参数的名称,只能通过参数的顺序进行绑定。
- 可读性:通过命名参数,SQL 语句更易于理解和维护。
- 灵活性:允许在同一个方法中有多个参数,并且每个参数都可以通过名称引用,而不是依赖于位置。
- 避免混淆:当有多个参数时,避免因参数顺序错误导致的问题。
然而,若您基于 Spring Boot 框架进行开发,并且您的项目继承自 spring-boot-starter-parent 父级工程,则该父级工程已预配置了以下插件。这使得在编译后能够保留方法的形式参数名称,从而允许框架在运行时访问这些参数名称。
<build><pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><parameters>true</parameters></configuration></plugin></plugins></pluginManagement>
</build>
2.2 #{} 占位符
#{} 是 MyBatis 中用于传递参数的占位符。它会将传入的参数值进行预编译处理,防止 SQL 注入攻击,并提高查询效率,以下是占位符与拼接符的区别
| 特性 | #{} 占位符 | ${} 拼接符 |
|---|---|---|
| 预编译 | 支持,防止 SQL 注入 | 不支持,容易导致 SQL 注入 |
| 类型转换 | 自动进行类型转换 | 不进行类型转换 |
| 适用场景 | 绑定参数值,如字段值、条件等 | 动态生成 SQL 语句,如表名、列名等 |
| 安全性 | 高,防止 SQL 注入 | 低,容易受到 SQL 注入攻击 |
| 性能 | 高,可以利用数据库的执行计划缓存 | 低,每次执行都需要重新解析和编译 |
| 灵活性 | 较低,适合固定结构的 SQL 语句 | 高,适合动态生成 SQL 语句 |
#{}占位符:用于传递参数值,支持预编译和类型转换,防止 SQL 注入,适合大多数场景。${}拼接符:用于直接拼接 SQL 字符串,不进行预编译和转义处理,适合动态生成 SQL 语句,但需特别注意安全性。
2.3 SQL 预编译
SQL 预编译(Prepared Statements)是指在执行 SQL 语句之前,先将其编译成数据库可以识别的执行计划,然后在实际执行时只需要传递参数即可。这种方式不仅可以提高查询效率,还能有效防止 SQL 注入攻击。
- 安全性:通过预编译机制,参数会被安全地传递到数据库,避免了直接拼接 SQL 字符串带来的 SQL 注入风险。
- 性能提升:对于重复执行的 SQL 语句,数据库可以缓存并重用执行计划,减少解析和编译的时间开销。
- 简化开发:开发者无需手动编写复杂的 SQL 语句拼接逻辑,减少了出错的可能性。
3. 配置 MyBatis XML 映射文件(可选)
使用 MyBatis 的注解,主要是来完成一些简单的增删改查功能。如果需要实现复杂的 SQL 功能,建议使用 XML 配置映射语句。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.itheima.mapper.UserMapper"><!-- 根据ID删除用户 --><select id="deleteById" parameterType="int" resultType="com.itheima.pojo.User">SELECT * FROM User WHERE id = #{id}</select><!-- 查询所有用户 --><select id="findAll" resultType="com.itheima.pojo.User">SELECT * FROM User</select>
3.1 默认规则
XML映射文件的名称与 Mapper 接口名称一致,并且将XML映射文件和 Mapper 接口放置在相同包下(同包同名)。XML映射文件的namespace属性为 Mapper 接口全限定名一致。XML映射文件中 sql 语句的id与 Mapper 接口中的方法名一致,并保持返回类型一致。

4. 配置 MyBatis 主配置文件
application.properties
spring.application.name=springboot-mybatis-quickstart
spring.datasource.url=jdbc:mysql://localhost:3306/userdb
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=mq20011103
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
这段配置文件是典型的 Spring Boot 应用程序中的 application.properties 或 application.yml 文件的一部分,用于配置应用程序的名称、数据源连接信息以及 MyBatis 的日志实现。下面是对每个配置项的详细解析:
4.1 Properties配置项解析
-
spring.application.name=springboot-mybatis-quickstart -
作用:设置应用程序的名称。
-
解释:这个属性定义了应用的名称,通常用于在日志、监控工具和其他地方标识该应用。在这个例子中,应用的名称为
springboot-mybatis-quickstart。 -
spring.datasource.url=jdbc:mysql://localhost:3306/userdb -
作用:设置数据库连接的 URL。
-
解释:这个属性指定了要连接的数据库的 JDBC URL。这里的 URL 表示连接到本地 (
localhost) MySQL 数据库服务器上的userdb数据库,端口号为 3306。 -
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver -
作用:设置数据库驱动类名。
-
解释:这个属性指定了用于连接数据库的 JDBC 驱动类。对于 MySQL 数据库,驱动类名为
com.mysql.cj.jdbc.Driver,这是 MySQL Connector/J 提供的驱动类。 -
spring.datasource.username=root -
作用:设置数据库用户名。
-
解释:这个属性指定了连接数据库时使用的用户名。在这个例子中,用户名为
root。 -
spring.datasource.password=mq20011103 -
作用:设置数据库密码。
-
解释:这个属性指定了连接数据库时使用的密码。在这个例子中,密码为
mq20011103。请注意,实际生产环境中应确保密码的安全性,避免直接硬编码在配置文件中。 -
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl -
作用:设置 MyBatis 的日志实现类。
-
解释:这个属性指定了 MyBatis 使用的日志实现类。
org.apache.ibatis.logging.stdout.StdOutImpl表示将 MyBatis 的日志输出到标准输出(控制台)。这有助于调试和查看 SQL 执行情况。
4.2 Properties 和 YAML/YML 配置文件的对比
| 特性 | Properties 文件 | YAML 文件 |
|---|---|---|
| 语法 | 扁平化键值对 | 层次结构化,使用缩进 |
| 可读性 | 较低,尤其是复杂配置 | 高,结构清晰 |
| 维护性 | 较低,特别是对于嵌套配置 | 高,嵌套结构易于管理 |
| 数据类型支持 | 仅支持字符串,需手动转换其他类型 | 支持多种数据类型,自动类型转换 |
| 缩进敏感性 | 不敏感 | 敏感,必须保持一致的缩进 |
| 使用场景 | 简单配置,传统应用 | 复杂配置,现代框架如 Spring Boot |
application.yaml/yml
spring:application:name: springboot-mybatis-quickstartdatasource:url: jdbc:mysql://localhost:3306/userdbdriver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: mq20011103mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
5. 编写测试代码
编写一个简单的测试类来验证这些操作是否正常工作:
package com.itheima;import com.itheima.mapper.UserMapper;
import com.itheima.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;import java.util.List;@SpringBootTest
class AliyunMybatisQuickstartApplicationTests {@Autowiredprivate UserMapper userMapper;@Testpublic void testFindAll(){List<User> userList = userMapper.findAll();userList.forEach(System.out::println);}/*** 测试删除*/@Testpublic void testDeleteById(){Integer i = userMapper.deleteById(4);System.out.println("执行完毕, 影响的记录数: " + i);}/*** 测试新增*/@Testpublic void testInsert(){User user = new User(null,"gaoyuanyuan","666888","高圆圆", 18);userMapper.insert(user);}/*** 测试更新*/@Testpublic void testUpdate(){User user = new User(1,"zhouyu","666888","周瑜", 20);userMapper.update(user);}/*** 测试查询*/@Testpublic void testSelect(){User user = userMapper.findByUsernameAndPassword("zhouyu", "666888");System.out.println(user);}}
5.1 @SpringBootTest
@SpringBootTest 是一个用于集成测试的注解,它会启动整个 Spring Boot 应用程序上下文(ApplicationContext),以便在测试环境中进行依赖注入和其他 Spring 功能的测试。
- 启动整个应用程序:当使用
@SpringBootTest注解时,Spring Boot 会自动创建并启动一个完整的应用程序上下文,类似于实际运行的应用程序。 - 自动配置:该注解会自动加载应用程序的配置文件(如
application.properties或application.yml),并根据这些配置初始化相应的 Bean。 - 依赖注入:允许在测试类中使用
@Autowired注解来注入需要测试的组件或服务。
5.2 @Autowired
@Autowired 是一个用于依赖注入的注解,它可以自动将所需的依赖项注入到类中。
- 自动注入:通过
@Autowired注解,Spring 容器会自动查找匹配的 Bean 并将其注入到目标字段、构造函数或方法参数中。 - 字段注入:可以直接在字段上使用
@Autowired,如示例中的userMapper字段。 - 构造函数注入:也可以在构造函数上使用
@Autowired,这种方式通常被认为更安全和推荐。 - Setter 方法注入:可以在 setter 方法上使用
@Autowired,但这种方式较少使用。
5.3 userList.forEach(System.out::println)
userList.forEach(System.out::println); 这行代码使用了 Java 8 引入的 方法引用 和 Lambda 表达式,目的是对 userList 中的每一个元素调用 System.out.println() 方法进行打印。
- 等效的 Lambda 表达式 如果你不使用方法引用,可以使用 Lambda 表达式来实现相同的功能:
userList.forEach(user -> System.out.println(user));
相关文章:
Mybatis快速入门与核心知识总结
Mybatis 1. 实体类(Entity Class)1.1 实体类的定义1.2 简化编写1.2.1 Data1.2.2 AllArgsConstructor1.2.3 NoArgsConstructor 2. 创建 Mapper 接口2.1 Param2.2 #{} 占位符2.3 SQL 预编译 3. 配置 MyBatis XML 映射文件(可选)3.1 …...
畅聊deepseek-r1,SiliconFlow 硅基流动注册+使用
文章目录 SiliconFlow 硅基流动注册使用注册创建API密钥使用网页端使用代码调用api调用支持的模型 SiliconFlow 硅基流动注册使用 注册 硅基流动官网 https://cloud.siliconflow.cn/i/XcgtUixn 注册流程 切换中文 邀请码: XcgtUixn 创建API密钥 账户管理 --&g…...
一个基于ESP32S3和INMP441麦克风实现音频强度控制RGB灯带律动的代码及效果展示
一个基于ESP32S3和INMP441麦克风实现音频强度控制RGB灯带律动的代码示例,使用Arduino语言: 硬件连接 INMP441 VCC → ESP32的3.3VINMP441 GND → ESP32的GNDINMP441 SCK → ESP32的GPIO 17INMP441 WS → ESP32的GPIO 18INMP441 SD → ESP32的GPIO 16RG…...
Springboot 中如何使用Sentinel
在 Spring Boot 中使用 Sentinel 非常方便,Spring Cloud Alibaba 提供了 spring-cloud-starter-alibaba-sentinel 组件,可以快速将 Sentinel 集成到你的 Spring Boot 应用中,并利用其强大的流量控制和容错能力。 下面是一个详细的步骤指南 …...
访问Elasticsearch服务 curl ip 端口可以 浏览器不可以
LINUX学习 在虚拟机上面的linux上面用docker 部署Elasticsearch项目后,在linux系统内部用curl ip 端口地址的形式可以访问到Elasticsearch。可以返回数据。 但是在本机的浏览器中输入ip 端口,会报错,找不到服务。 ping 和 trelnet均不通。 …...
Curser2_解除机器码限制
# Curser1_无限白嫖试用次数 文末有所需工具下载地址 Cursor Device ID Changer 一个用于修改 Cursor 编辑器设备 ID 的跨平台工具集。当遇到设备 ID 锁定问题时,可用于重置设备标识。 功能特性 ✨ 支持 Windows 和 macOS 系统🔄 自动生成符合格式的…...
人工智能与低代码如何重新定义企业数字化转型?
引言:数字化转型的挑战与机遇 在全球化和信息化的浪潮中,数字化转型已经成为企业保持竞争力和创新能力的必经之路。然而,尽管“数字化”听上去是一个充满未来感的词汇,落地的过程却往往充满困难。 首先,传统开发方式…...
arkTS基础
arkTS基础 // 变量声明 let hi: string hello; hi hello,world; // 常量声明 const hi: string hello;// ArkTS是一种静态类型语言,所有数据的类型都必须在编译时确定 // 如果一个变量或常量的声明包含了初始值,那么开发者就不需要显式指定其类型。…...
C++20中的std::atomic_ref
一、std::atomic_ref 我们在学习C11后的原子操作时,都需要提前定义好std::atomic变量,然后才可以在后续的应用程序中进行使用。原子操作的优势在很多场合下优势非常明显,所以这也使得很多开发者越来习惯使用原子变量。 但是,在实…...
四、自然语言处理_08Transformer翻译任务案例
0、前言 在Seq2Seq模型的学习过程中,做过一个文本翻译任务案例,多轮训练后,效果还算能看 Transformer作为NLP领域的扛把子,对于此类任务的处理会更为强大,下面将以基于Transformer模型来重新处理此任务,看…...
spring学习(使用spring加载properties文件信息)(spring自定义标签引入)
目录 一、博客引言。 二、基本配置准备。 (1)初步分析。 (2)初始spring配置文件。 三、spring自定义标签的引入。 (1)基本了解。 (2)引入新的命名空间:xmlns:context。 &…...
bigemap pro如何进行poi兴趣点搜索?
准备工具:BIGEMAP Pro是数据要素设计软件(DED),国产基础软件,大数据编辑、制图、多源数据要素类处理软件打开软件右上角选择分类搜索然后用矩形或者选择行政边界线选择需要查询的范围选中范围以后点击查询然后可以直接加载到地图然后图层右键数据导出矢量…...
Mybatis源码02 - 初始化基本过程(引导层部分)
初始化基本过程(引导层部分) 文章目录 初始化基本过程(引导层部分)一:初始化的方式及引入二:初始化方式-XML配置文件1:MyBatis初始化基本过程2:创建Configuration对象的过程2.1&…...
【Elasticsearch】bucket_sort
Elasticsearch 的bucket_sort聚合是一种管道聚合,用于对父多桶聚合(如terms、date_histogram、histogram等)的桶进行排序。以下是关于bucket_sort的详细说明: 1.基本功能 bucket_sort聚合可以对父聚合返回的桶进行排序ÿ…...
k8s证书过期怎么更新?
在 Kubernetes 集群中,证书过期可能导致集群不可用,尤其是 API Server、Controller Manager、Scheduler 等组件所使用的证书。为了恢复集群的正常运行,您需要更新这些证书。以下是更新 Kubernetes 证书的基本步骤: 1. 检查证书状…...
活动预告 |【Part 1】Microsoft 安全在线技术公开课:通过扩展检测和响应抵御威胁
课程介绍 通过 Microsoft Learn 免费参加 Microsoft 安全在线技术公开课,掌握创造新机遇所需的技能,加快对 Microsoft Cloud 技术的了解。参加我们举办的“通过扩展检测和响应抵御威胁”技术公开课活动,了解如何更好地在 Microsoft 365 Defen…...
AIGC-微头条爆款文案创作智能体完整指令(DeepSeek,豆包,千问,Kimi,GPT)
Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列AIGC(GPT、DeepSeek、豆包、千问、Kimi)👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资…...
C# 比较两个List集合内容是否相同
在 C# 中,要比较两个 List<T> 集合的内容是否相同,可以通过以下几种方法: 一、非自定义类的元素比较 1. 使用 SequenceEqual 方法(顺序和内容都相等) 顺序和内容都相等:使用 SequenceEqual。 usin…...
vue2 多页面pdf预览
使用pdfjs-dist预览pdf,实现预加载,滚动条翻页。pdfjs的版本很重要,换了好多版本,终于有一个能用的 node 20.18.1 "pdfjs-dist": "^2.2.228", vue页面代码如下 <template><div v-loading"loa…...
【python】matplotlib(animation)
文章目录 1、matplotlib.animation1.1、FuncAnimation1.2、修改 matplotlib 背景 2、matplotlib imageio2.1、折线图2.2、条形图2.3、散点图 3、参考 1、matplotlib.animation 1.1、FuncAnimation matplotlib.animation.FuncAnimation 是 Matplotlib 库中用于创建动画的一个…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
相机Camera日志实例分析之二:相机Camx【专业模式开启直方图拍照】单帧流程日志详解
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、场景操作步骤 二、日志基础关键字分级如下 三、场景日志如下: 一、场景操作步骤 操作步…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
STM32HAL库USART源代码解析及应用
STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...
Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「storms…...
