Mybatis-Plus简单介绍

article/2025/6/24 10:31:23

前一篇文章中,小编介绍到了Mybatis,以及它的增强工具,mybatis-generator。

那么为了再减少对于SQL语句的编写,那么mybatis的另一个增强工具也是做出了巨大努力。

Mybaits-Plus

Mybatis-Plus简称MP,它是一个Mybatis的增强工具之一,在Mybatis的基础上只做增强不做改变,为简化开发而生

,提高效率而生。

以下来自官方介绍的特性:

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

官方网站:

MyBatis-Plus �� 为简化开发而生

那么废话不多说,小编来介绍下,这个Mybatis-Plus如何快速上手。

快速上手

1.数据准备

该内容可以在navicat中操作

SQL
-- 删除数据库(如果存在)
DROP DATABASE IF EXISTS mybatis_test;

-- 创建数据库,并设置默认字符集为utf8mb4
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;

-- 使用创建的数据库
USE mybatis_test;

-- 删除表(如果存在)
DROP TABLE IF EXISTS user_info;

-- 创建用户信息表
CREATE TABLE `user_info` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `username` VARCHAR(127) NOT NULL,
    `password` VARCHAR(127) NOT NULL,
    `age` TINYINT(4) NOT NULL,
    `gender` TINYINT(4) DEFAULT '0' COMMENT '1-男 2-女 0-默认',
    `phone` VARCHAR(15) DEFAULT NULL,
    `delete_flag` TINYINT(4) DEFAULT 0 COMMENT '0-正常,1-删除',
    `create_time` DATETIME DEFAULT now(),
    `update_time` DATETIME DEFAULT now(),
    PRIMARY KEY (`id`)
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;

-- 插入用户数据
INSERT INTO mybatis_test.user_info(`username`, `password`, `age`, `gender`, `phone`)
VALUES ('admin', 'admin', 18, 1, '18612340001');

INSERT INTO mybatis_test.user_info(`username`, `password`, `age`, `gender`, `phone`)
VALUES ('zhangsan', 'zhangsan', 18, 1, '18612340002');

INSERT INTO mybatis_test.user_info(`username`, `password`, `age`, `gender`, `phone`)
VALUES ('lisi', 'lisi', 18, 1, '18612340003');

INSERT INTO mybatis_test.user_info(`username`, `password`, `age`, `gender`, `phone`)
VALUES ('wangwu', 'wangwu', 18, 1, '18612340004');

2.项目准备

创建一个Springboot项目

然后引入相关依赖

依赖引入(官网自有提供)

Spring Boot2:

XML
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.12</version>
</dependency>

Spring Boot3:

XML
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.12</version>
</dependency>

MySQL驱动:

XML
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <version>8.3.0</version>
</dependency>

3.配置文件:

application.yml:

YAML
spring:
  application:
    name: MybatisPlus
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: '9974'
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl    
    

application.properties:

Properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datesource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password='1234'
mybatis-plus.configuration.log-impl:org.apache.ibatis.logging.stdout.StdOutImpl

3.基本代码准备:


新建一个model包,新建一个UserInfo类

UserInfo:

Java
import lombok.Data;
import java.util.Date;
@Data
public class UserInfo {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
}

新建一个mapper包,同时新建一个UserInfoMapper

UserInfoMapper:

Java
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

至此,基本代码就写完了。

那么此时,如何使用呢?这里就不写接口了,在测试类中进行代码测试。

CRUD:

生成一个UserInfoMapperTest测试类

查询:

由于是mybatis-plus为我们提供了许多已经定制好的语句,这里直接就拿来用即可。

userInfoMapper

TypeScript
@SpringBootTest
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userInfoMapper;
    //查
    @Test
    void testSelectById(){
        System.out.println(userInfoMapper.selectById(1));
    }
  }

那么值得注意的是,查询出来的结果及其结果样式,与上篇文章查询的结果,区别不大,所以不做展示

同时想要更多的详细信息,了解select提供的参数,可以访问官网了解:https://baomidou.com/guides/data-interface/#select

增加:

TypeScript
//增
@Test
void testInsert(){
    UserInfo userinfo=new UserInfo();
    userinfo.setUsername("python");
    userinfo.setPassword("123456");
    userinfo.setAge(19);
    userinfo.setGender(1);
    //返回结果为影响的行数
    System.out.println(userInfoMapper.insert(userinfo));
}

在增加这里,要注意一点,如若未指明ID(存在主键),那么mybatis-plus会通过一些策略进行生成ID

默认策略:

MyBatis-Plus 默认采用 IdType.ASSIGN_ID 作为主键生成策略,它会使用雪花算法(Snowflake)生成一个64位的Long型数字作为唯一ID。这意味着即使你没有手动为实体类设置ID值,在插入数据时MyBatis-Plus也会自动生成一个唯一的ID。

自定义主键生成策略:

Java
//存在自增ID,要显式告诉mybatis-plus
@TableId(type = IdType.AUTO)
private Integer id;

删除:

Java
//删除
@Test
void testDelete(){
    System.out.println(userInfoMapper.deleteById(9));
}

这里是简单演示下通过ID删除,它的参数还可以传是入一个列表(进行批量删除)等等,读者可以进行官网详细阅读。

https://baomidou.com/guides/data-interface/#delete

更新:

TypeScript
//更新
@Test
void testUpdate(){
    UserInfo userinfo=new UserInfo();
    userinfo.setId(9);
    userinfo.setUsername("JS");
    userinfo.setPassword("JS1234");
    userinfo.setAge(20);
    System.out.println(userInfoMapper.updateById(userinfo));
}

更多详细方法,访问该官网:https://baomidou.com/guides/data-interface/#update-1

那么在mybatis中,我们演示了,如何可以重命名参数,那么mybatis-plus提供了对应的注解进行修改。

重命名表名:

Java
@Data
@TableName("user_Info")
public class UserInfo {
}

重命名字段名:

TypeScript
@Data
@TableName("user_Info")
public class UserInfo {
    //存在自增ID,要显式告诉plus
    @TableId(type = IdType.AUTO)
    private Integer id;
    @TableField("username")
    private String username;
 }

以上是简单的增删查改语句,那么遇到一些复杂的话,那么就是需要用到条件构造器了。

条件构造器:


以下是来自官方的解释:

MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件。Wrapper 类允许开发者以链式调用的方式构造查询条件,无需编写繁琐的 SQL 语句,从而提高开发效率并减少 SQL 注入的风险。

在 MyBatis-Plus 中,Wrapper 类是构建查询和更新条件的核心工具。以下是主要的 Wrapper 类及其功能:

  • AbstractWrapper:这是一个抽象基类,提供了所有 Wrapper 类共有的方法和属性。它定义了条件构造的基本逻辑,包括字段(column)、值(value)、操作符(condition)等。所有的 QueryWrapper、UpdateWrapper、LambdaQueryWrapper 和 LambdaUpdateWrapper 都继承自 AbstractWrapper。
  • QueryWrapper:专门用于构造查询条件,支持基本的等于、不等于、大于、小于等各种常见操作。它允许你以链式调用的方式添加多个查询条件,并且可以组合使用 and 和 or 逻辑。
  • UpdateWrapper:用于构造更新条件,可以在更新数据时指定条件。与 QueryWrapper 类似,它也支持链式调用和逻辑组合。使用 UpdateWrapper 可以在不创建实体对象的情况下,直接设置更新字段和条件。
  • LambdaQueryWrapper:这是一个基于 Lambda 表达式的查询条件构造器,它通过 Lambda 表达式来引用实体类的属性,从而避免了硬编码字段名。这种方式提高了代码的可读性和可维护性,尤其是在字段名可能发生变化的情况下。
  • LambdaUpdateWrapper:类似于 LambdaQueryWrapper,LambdaUpdateWrapper 是基于 Lambda 表达式的更新条件构造器。它允许你使用 Lambda 表达式来指定更新字段和条件,同样避免了硬编码字段名的问题。

那么接下来看看如何使用吧。

QueryWrapper:

构建查询条件,这里的查询条件不仅仅作用于select语句。

场景一:

查询age==18,以及模糊匹配username='java'

TypeScript
    @Test
    void testQueryWrapper(){
        QueryWrapper<UserInfo> queryWrapper=new QueryWrapper<>();
        queryWrapper.select("id,username,password,age,gender")
                .eq("age",18)
                .like("username","python");
        userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
    }        

System.out::println:

这个是Java8引入的方法引用,用于直接引用已有的方法,它是属于函数式编程的一部分。

对于方法引用,以及函数式编程,解释如下:

函数式编程:

函数式编程 是一种编程范式(Programming Paradigm),它强调“函数是一等公民”,即函数可以像变量一样被传递、赋值、作为参数或返回值。

方法引用:

方法引用 是对已有方法的引用,它可以简化 Lambda 表达式的写法,使代码更清晰。

常见的方法引用类型:

点击图片可查看完整电子表格

like:左右通配匹配。

likeRight:右匹配:name%

likeLeft:左匹配:%name

场景二:

年龄小于21岁以下的,把deleteFlag设置为1(通过对象属性设置)

TypeScript
@Test
void testQueryWrapper2() {
    QueryWrapper<UserInfo> queryWrapper=new QueryWrapper<>();
    UserInfo userInfo=new UserInfo();
    queryWrapper.lt("age",21);
    userInfo.setDeleteFlag(1);
    System.out.println(userInfoMapper.update(userInfo, queryWrapper));
}

场景三:

删除年龄等于21的

Java
@Test
void testQueryWrapper3() {
    QueryWrapper<UserInfo> queryWrapper=new QueryWrapper<>();
    queryWrapper.eq("age",21);
    System.out.println(userInfoMapper.delete(queryWrapper));

}

UpdateWrapper:
场景1:

设置年龄21,当名字为java的时候

TypeScript
@Test
void updateQueryWrapper(){
    UpdateWrapper<UserInfo> updateWrapper=new UpdateWrapper<>();
    updateWrapper.set("age",21)
            .eq("username","java");
    System.out.println(userInfoMapper.update(updateWrapper));
}

场景二:

设置年龄40,gender=1,通过批量修改

TypeScript
@Test
void updateQueryWrapper2(){
    UpdateWrapper<UserInfo> updateWrapper=new UpdateWrapper<>();
    updateWrapper.set("age",40).set("gender",1)
            .in("id", List.of(4,6,7));
    System.out.println(userInfoMapper.update(updateWrapper));
}

场景三:

设置SQL片段语句,age=age+10,通过ID进行批量修改

TypeScript
@Test
void updateWrapper3(){
    UpdateWrapper<UserInfo> updateWrapper=new UpdateWrapper<>();
    updateWrapper.setSql("age=age+10")
            .in("id",List.of(4,6,7));
    System.out.println(userInfoMapper.update(updateWrapper));
}

lambdaWrapper:

LambdaQueryWrapper:

示例,查询数据库中,年龄等于18的相关信息:

Java
@Test
void lambdaQueryWrapper(){
    LambdaQueryWrapper<UserInfo> queryWrapper=new LambdaQueryWrapper<>();
    System.out.println(queryWrapper.select(UserInfo::getId, UserInfo::getUsername,
                    UserInfo::getAge, UserInfo::getGender,UserInfo::getCreateTime)
            .eq(UserInfo::getAge, 18));

    userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
}

LamdaUpdateWrapper:

示例:修改数据库密码和年龄,当名字为王五的时候

这里使用UpdateWrapper.lambda()方法去做

Java
@Test
void lambdaUpdateWrapper(){
   UpdateWrapper<UserInfo> updateWrapper=new UpdateWrapper<>();
   updateWrapper.lambda()
           .set(UserInfo::getPassword,"12345")
           .set(UserInfo::getAge,"20")
           .eq(UserInfo::getUsername,"王五");

    System.out.println(userInfoMapper.update(updateWrapper));
}

对于使用LambdaUpdateWrapperd类来说,上面内容只需去掉.lamda()即可

那么对于条件构造器这里呢,小编就讲到这,详细的可以看官方文档:https://baomidou.com/guides/wrapper/#_top

既然Mybatis-plus这么好用,那么提供的方法是否就一定满足业务需求了呢?

显然,是很难做到的,所以Mybatis也是支持自定义SQL语句。

自定义SQL语句

简单介绍几个场景

1.查询username等于java的

Java
 */
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
        //自定义SQL语句
        @Select("select id,username,password,age " +
                "from user_info ${ew.customSqlSegment}")
        List<UserInfo> selectByCustom(@Param(Constants.WRAPPER)Wrapper wrapper);
    }

测试类:

TypeScript

@Test
void selectByCustom() {
    QueryWrapper<UserInfo> queryWrapper=new QueryWrapper<>();
    queryWrapper.eq("username","java");
    userInfoMapper.selectByCustom(queryWrapper).forEach(System.out::println);
}

@Param(Constants.WRAPPER):

Constants.WRAPPER="ew",写上这个,是告诉Mybatis-plus,这个是Wrapper对象,并且它的参数固定名为

"ew"(即 Entity Wrapper 的缩写)

${ew.customSqlSegment}:

这是一个占位符把传进来的 Wrapper 对象转换成 SQL 条件语句,并插入到当前 SQL 的位置上。

$符号内的ew是来自@Parm里的

值得注意的是,最好是#{},为了防止SQL注入的占位符。

2.通过XML来查询

配置文件:

YAML
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:/mapper/**/*.xml

UserInfoMapper接口类:

Java
List<UserInfo> selectByCustom2(@Param(Constants.WRAPPER)Wrapper wrapper);

xml文件:

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.nanxi.mybatisplus.mapper.UserInfoMapper">
    <select id="selectByCustom2" resultType="com.nanxi.mybatisplus.model.UserInfo">
        select id,username,password,age from
            user_info ${ew.customSqlSegment}
    </select>
</mapper>

测试类:

TypeScript
@Test
void selectByCustom2() {
    QueryWrapper<UserInfo> queryWrapper=new QueryWrapper<>();
    queryWrapper.eq("username","java");
    userInfoMapper.selectByCustom2(queryWrapper).forEach(System.out::println);
}

3.表达式赋值

Java

@Update("update user_info set age=age+#{age} ${ew.customSqlSegment}")
Integer selectByCustom3(@Param("age") Integer age,@Param(Constants.WRAPPER)Wrapper wrapper);

测试类:

Java

@Test
void selectByCustom3() {
    UpdateWrapper<UserInfo> updateWrapper=new UpdateWrapper<>();
    updateWrapper.eq("username","java");

    System.out.println(userInfoMapper.selectByCustom3(10, updateWrapper));
}

至此,对于Mybatis-plus的简单到这里,更多信息,可以访问官网进行详细了解


http://www.hkcw.cn/article/XpyXPUvXYg.shtml

相关文章

LLm中 float16和 float32 区别,为什么训练不能采用float16--梯度消失

LLm中 float16和 float32 区别,为什么训练不能采用float16–梯度消失 在深度学习中,使用 float16(半精度)而非 float32(单精度)进行训练时,数值范围和精度的差异可能导致一系列问题,特别是当损失值达到 0.0001 这种较小时。以下是具体分析: 1. float16 与 float32 的…

Vue2之2组件通信

文章目录 什么是组件通信不同的组件关系 和 组件通信方案分类组件关系分类&#xff1a;组件通信方案分类 父子通信流程图&#xff1a;父传子子传父非父子通信 (拓展) - event bus 事件总线非父子通信 (拓展) - provide & inject 深入学习prop属性prop接收多个值props 是只读…

Qt -下载Qt6与OpenCV

博客主页&#xff1a;【夜泉_ly】 本文专栏&#xff1a;【暂无】 欢迎点赞&#x1f44d;收藏⭐关注❤️ 前言 呃啊&#xff0c;本来就想在 Qt 里简单几个 OpenVC 的函数&#xff0c;没想到一搞就是一天。 我之前的开发环境是 Qt 5.14.2&#xff0c;使用 MinGW 7.3.0 64-bit 编…

8088单板机C语言sprintf()格式化串口输出---Prj04

#include "tiny_stdarg.h" // 使用自定义可变参数实现#define ADR_273 0x0200 #define ADR_244 0x0400 #define LED_PORT 0x800 #define PC16550_THR 0x1f0 #define PC16550_LSR 0x1f5 / //基本的IO操作函数 / char str[]"Hello World! 20250531 Ve…

HTML实现端午节主题网站:龙舟争渡,凭吊祭江诵君赋。

名人说&#xff1a;龙舟争渡&#xff0c;助威呐喊&#xff0c;凭吊祭江诵君赋。——苏轼《六幺令天中节》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、项目概览&#xff1a;传统与现代的技术碰撞1. 核心特…

YOLOv10改进|爆改模型|涨点|在颈部网络添加结合部分卷积PConv和SDI融合方法的PSDI特征融合层(附代码+修改教程)

一、文本介绍 本文修改的模型是YOLOv10&#xff0c;YOLOv10无需非极大值抑制&#xff08;NMS&#xff09;进行后处理&#xff0c;其推理速度以及参数量上都优于现有的模型。然而&#xff0c;针对某些目标检测任务中需要同时处理多尺度目标的挑战&#xff0c;YOLOv10 在此类场景…

Redis最佳实践——安全与稳定性保障之高可用架构详解

全面详解 Java 中 Redis 在电商应用的高可用架构设计 一、高可用架构核心模型 1. 多层级高可用体系 #mermaid-svg-Ffzq72Onkv7wgNKQ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Ffzq72Onkv7wgNKQ .error-icon{f…

虚拟存储器:将十六进制逻辑地址 0A5C、103C、1A5C 转换成物理地址(2)

转换成十进制&#xff08;分步骤解析&#xff09; 确定页号和偏移的计算方式 页大小1KB 2^10&#xff0c;逻辑地址中 页号 逻辑地址 1024&#xff08;整数除法&#xff09;&#xff0c;页内偏移 逻辑地址 % 1024。物理地址 物理块号 1024 页内偏移&#xff0c;其中物理块…

【HTML】基础学习【数据分析全栈攻略:爬虫+处理+可视化+报告】

- 第 102 篇 - Date: 2025 - 05 - 31 Author: 郑龙浩/仟墨 文章目录 HTML 基础学习一 了解HTML二 HTML的结构三 HTML标签1 标题2 文本段落3 换行4 加粗、斜体、下划线5 插入图片6 添加链接7 容器8 列表9 表格10 class类 HTML 基础学习 一 了解HTML 一个网页分为为三部分&…

吴恩达MCP课程(2):research_server

目录 代码代码解释导入模块常量定义MCP服务器初始化工具函数定义1. search_papers 函数2. extract_info 函数 主程序总结 运行示例 代码 import arxiv import json import os from typing import List from mcp.server.fastmcp import FastMCPPAPER_DIR "papers"mc…

【数据结构】——二叉树--链式结构

一、实现链式结构二叉树 二叉树的链式结构&#xff0c;那么从名字上我们就知道我们这个二叉树的底层是使用链表来实现的&#xff0c;前面我们的二叉树是通过数组来实现的&#xff0c;那么在其是完全二叉树的情况下&#xff0c;此时我们使用数组来实现就会使得其空间浪费较少&a…

netty中的EventLoop原理解析

一起来学netty 1. EventLoop的基本概念2. EventLoop的核心组件3. EventLoop的工作流程4. EventLoop与Channel的关系5. EventLoop的实现类6. EventLoop的线程模型7. EventLoop的优点8. EventLoop的注意事项9. 示例代码10.异步编程模型解析异步编程的定义异步编程的核心特点异步编…

使用Java实现简单的计算机案例

第一个案例我决定做一个简单的“简易计算器”&#xff0c;来开启编程之旅。为什么我会选择这个案例来作为第一个Java案例呢&#xff1f;大家可别小看这个小小的计算器&#xff0c;它既简单又实用。通过这个案例&#xff0c;大家可以学会或着练习如何处理用户输入、如何实现基本…

流媒体基础分析:延迟分析与安全性保障

在流媒体传输过程中&#xff0c;延迟和安全性是两个至关重要的方面。它们直接影响着用户的观看体验和内容的版权保护。本文将深入分析延迟的来源与追赶技术&#xff0c;并探讨流媒体传输的安全性保障手段。 1. 延迟分析 1.1 延迟说明 延迟是流媒体传输中不可避免的问题&#…

S32K3 工具篇9:如何在无源码情况下灵活调试elf文件

S32K3 工具篇9&#xff1a;如何在无源码情况下灵活调试elf文件 一&#xff0c;文档简介二&#xff0c; 功能实现2.1 代码工具准备2.2 elf修改功能实现&#xff1a;Fun2功能跳过2.2.1 PC越过Fun22.2.2 Fun2替换为nop 2.3 elf修改功能实现&#xff1a;Fun4替换Fun2入口2.3.1 link…

树莓派PWM控制LED灯

目录 一、什么是PWM二、树莓派引脚图三、命令行控制LED灯四、PWM控制LED呼吸灯 一、什么是PWM PWM&#xff08;Pulse Width Modulation&#xff0c;脉冲宽度调制&#xff09;是一种通过调节数字信号的占空比&#xff08;Duty Cycle&#xff09;来模拟模拟信号的技术。它通过快…

第十四章 MQTT订阅

系列文章目录 系列文章目录 第一章 总体概述 第二章 在实体机上安装ubuntu 第三章 Windows远程连接ubuntu 第四章 使用Docker安装和运行EMQX 第五章 Docker卸载EMQX 第六章 EMQX客户端MQTTX Desktop的安装与使用 第七章 EMQX客户端MQTTX CLI的安装与使用 第八章 Wireshark工具…

六.MySQL增删查改

CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09; 一.增 insert 1.单行数据 全列插入 语法特点&#xff1a;不指定字段名&#xff0c;按表结构字段顺序依次提供所有值。 注意&#xff1a;字段顺序必须与表定义一…

TKernel模块--自定义RTTI,对象句柄,引用计数

TKernel模块–RTTI&#xff0c;对象句柄&#xff0c;引用计数 1.DEFINE_STANDARD_HANDLE(x1, x2) #define DEFINE_STANDARD_HANDLE(C1,C2) DEFINE_STANDARD_HANDLECLASS(C1,C2,Standard_Transient)其中&#xff1a; #define DEFINE_STANDARD_HANDLECLASS(C1,C2,BC) class C1…

关于TongWeb数据源兼容mysql驱动的注意事项

问题现象&#xff1a; TongWeb数据源在采用mysql驱动的国产数据库时&#xff0c;因数据库慢报超时为数据源配置参数的 validation-query-timeout值5秒&#xff0c;而不是期望的maxwait、connectiontimeout值。 The last packet successfully received from the server was 5,0…