disgare 的博客
首页
博客
分类
标签
首页
博客
分类
标签
  • 网络

    • 计算机网络学习笔记
    • 网络安全相关
    • 域名和子网掩码
    • CORS 跨域资源共享
    • DNS、HTTP 与 HTTPS
    • Server-Sent Events (SSE)
    • WebSocket 长连接
  • 计算机基础

    • 操作系统 IO 相关知识
    • 操作系统学习笔记
    • 程序的机器级表示
    • 音频文件基础
    • 正则表达式相关概念
    • ffmpeg 的安装以及实现音频切分功能
    • Hex 和 Base64 编码
    • XML 的使用
  • 数据结构与算法

    • 动态规划算法学习笔记
    • 基于比较的排序算法的最坏情况下的最优下界为什么是O(nlogn)
    • 集合与数据结构学习笔记
    • 面试常见算法总结
    • 算法导论第二部分排序学习笔记
    • 算法导论第一部分学习笔记
  • Java

    • 对象之间的映射与转换
    • 反射学习笔记
    • 泛型相关概念
    • 关于 boolean 类型的坑
    • 如何使用 lambda 表达式实现排序
    • CompletableFuture 相关用法
    • CompletableFuture 源码浅要阅读
    • FutureTask 源码阅读
    • Guava 常用 API
    • Guava 源码阅读:Multimap 相关
    • Jackson 的各种使用
    • Java 的 Excel 相关操作
    • java 的常见性能问题分析以及出现场景
    • java 基础知识
    • JAVA 枚举的基础和原理
    • Java 图片文件上传下载处理
    • Java 序列化
    • Java 异常
    • Java 语法糖
    • Java 中关于字符串处理的常用方法
    • Java 中强、软、弱、虚引用
    • JAVA 注解小结
    • Java Http 访问框架
    • Java Stream 的使用
    • Java8 新特性
    • netty 学习笔记
    • Scanner 的各种用法
    • Servlet 学习笔记
    • String、StringBuffer、StringBuilder 学习笔记
  • JVM

    • 虚拟机执行子系统
    • JVM 自动内存管理
    • Linux 中 JVM 常用工具以及常见问题解决思路
  • Linux

    • crontab 表达式
    • Linux 常见命令
    • Linux 文件系统
  • 中间件

    • 关于定时任务原理
    • 详解 kafka
    • ES 搜索引擎
    • flink 提交流程
    • Grape-RAG
    • Hadoop 基础原理
  • 多线程

    • 多线程基础学习笔记
    • 简单了解并发集合
    • 如何手写单例
    • 深入理解 java 多线程安全
    • 生产者消费者问题
    • 线程池作用、用法以及原理
    • AQS 组件
    • ThreadLocal 原理以及使用
  • 非关系型数据库

    • Redis 集群
    • Redis 数据结构、对象与数据库
    • Redis 学习笔记
  • 关系型数据库

    • B+ 树的插入、删除和数据页分裂机制
    • MySQL 的 binglog、redolog、undolog
    • MySQL 的记录存储结构、存储引擎与 Buffer Pool
    • MySQL 基本的特性
    • MySQL 开发规范
    • MySQL 事务与锁与 MVCC
    • MySQL 数据类型、字符集相关内容
    • MySQL 索引与索引优化
    • PostgreSQL 更新数据时 HOT优化
    • PostgreSQL 相关用法
  • Python

    • Python 基础语法
    • Python 学习
  • Spring 项目

    • Lombok 的常用注解
    • maven 小结
    • MyBatis 框架的使用
    • MyBatis 重要知识点总结
    • MybatisPlus 的使用
      • 实体类
        • 别名处理、主键自增 @TableId
        • 表名处理 @TableName
        • 自动填充、别名处理、类型转换 @TableField
        • 逻辑删除 @TableLogic
      • 通用枚举 @EnumValue
      • 插件
        • 分页插件
        • 乐观锁(Version)
      • 条件构造器
      • 代码生成器
    • Spring 框架基础使用
    • Spring 事务相关
    • Spring IOC 的原理及源码
    • Spring AOP 的使用和原理
    • SpringBoot 的原理
    • SpringBoot 基础使用
    • SpringWeb 重要知识点
  • 分布式

    • 初步了解 docker
    • 从 ACID 到 BASE 事务处理的实现
    • 访问远程服务
    • 分布式 id
    • 分布式缓存相关问题
    • 分布式集群理论和分布式事务协议
    • 分布式架构的观测
    • 分布式一致性算法
    • 负载均衡 Load Balancing
    • 关于分布式系统 RPC 中高可用功能的实现
    • 集群间数据同步的目的
    • 三高问题下的系统优化
    • 数据库分库分表
    • 详解 Spring Cloud
    • Dubbo 基础概念
    • Gossip 协议
    • nginx 学习笔记
    • Protobuf 通信协议
    • Zookeeper 基础学习
  • 架构设计

    • 参数校验与异常处理
    • 抽象方法与设计模式
    • 代码整洁之道
    • 权限系统设计
    • 用低内存处理大量数据
    • 设计模式——策略模式
    • 设计模式——过滤器模式在 Spring 中的实践
    • 状态模式
    • 统一结果返回
    • 为什么要打日志?怎么打日志?打什么日志?
    • 运维监控常见指标含义
    • 资深研发进阶
    • DDD 架构学习笔记
    • Java 常用的规则引擎
    • MVC 架构学习笔记
  • AI

    • 如何编写 Prompt
    • Agent 工程架构
    • LLM 相关内容
    • NLP 相关知识
    • vibe coding 最佳实践
    • windows 下 ollama 迁移到 D 盘
  • 开发工具

    • 如何画时序图、流程图、状态流转图
    • excel 关于 =vlookup 的用法
    • git 的学习以及使用
    • IDEA 插件推荐
    • IDEA 常用快捷键以及调试
    • Shell 脚本
    • swagger 的使用
  • 前端

    • 简单了解前端页面开发
    • 伪静态是什么
    • GitHub Pages 部署教程
    • Vercel 部署教程
    • vue-admin-template 简单使用
    • VuePress 博客搭建指南
  • 项目

    • 面试刷题网——技术方案
    • 影视资源聚合站——技术方案
  • 问题记录

    • 定时任务单线程消费 redis 中数据导致消费能力不足
    • 提供可传递的易受攻击的依赖项
    • Liteflow 在 SpringBoot 启动时无法注入组件问题 couldn‘t find chain with the id[THEN(NodeComponent)]
  • 金融

    • 股票分析——关于电力
    • 股票技术面——量价关系
    • 股票技术面——盘口
    • 股票技术面——基础
    • 基础的金融知识
    • 基金与股票
    • 韭菜的自我总结
    • 聊聊价值投资
  • 其他

    • 程序员职场工作需要注意什么
    • 创业全链路SOP:从灵光一现到系统化增长的实战指南
    • 观罗翔讲刑法随笔
    • 价格和价值
    • 立直麻将牌效益理论
    • 梅花易数学习笔记
    • 压力管理
2022-02-03
Spring 项目
目录

MybatisPlus 的使用

MP 是非常优秀的持久层辅助框架,如果说 Mybatis 是处理数据在应用与数据库之间转换的各种情况,MP 就是对 Mybatis 的各种常用功能做进一步封装,让我们更加注重业务逻辑

在 SpringBoot 中的使用步骤相当简单,首先引入相关依赖

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
        </dependency>
1
2
3
4

在 easyCode 中可以使用 mybatis-plus 一键生成,如果使用默认生成策略注意主键要加 @TableId,Dao 层接口加 @Mapper 或者 @Repository

此时可以使用 MP 的基础功能,使用其他功能配置其他东西即可

具体方法的使用移步官方文档:https://www.mybatis-plus.com/

# 实体类

MP 它的底层原理大致为根据 PO 实体类尝试反向生成表结构,并且根据这些信息生成 SQL 语句,因此实体类相当重要

我们经常遇到实体类与表名或者属性不一致的问题,导致 MP 使用错误

# 别名处理、主键自增 @TableId

由于MP默认通过ID查询,但是很多时候数据库和POJO都不会把主键命名为id,使用 @TableId 这个注解可以让这个问题解决

这个注解有两个属性,value 是数据库主键名(默认的主键叫 id,如果数据库中的主键不叫 id 需要使用 value 显示映射),type 是指定主键自增策略

public @interface TableId {
    String value() default "";

    IdType type() default IdType.NONE;
}
1
2
3
4
5

在 POJO 的属性上使用这个注解

    @TableId(value = "no", type = IdType.AUTO)
    private String no;
1
2

主键推荐使用 Integer,在数据库中推荐使用 int 类后加长度,因为这样才可以使用自动主键策略

使用MP时,不用写主键,会自动给用户生成ID值,也可以在TableId注解中配置主键生成策略

在 IdType 类中定义了这些策略,Depercated 代表已被弃用

	//自动增长,主键是数字类型才可用,每次成长1
    AUTO(0),
    //无策略,需要用户手动输入
    NONE(1),
    //需要用户手动输入
    INPUT(2),
    //生成19位数字,字符串和数字型都可以使用
    ASSIGN_ID(3),
    //根据一定算法生成随机唯一ID
    ASSIGN_UUID(4),
    //之前MP默认生成算法,使用雪花算法,主键是数字类时使用
    @Deprecated
    ID_WORKER(3),
    //之前MP默认生成算法,使用雪花算法,主键是字符串时使用
    @Deprecated
    ID_WORKER_STR(3),
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 表名处理 @TableName

如果表名和 POJO 名不一样会出现错误,不过使用 TableName 注解就可以解决,可以在实体类上加 @TableName 来显示指定需要映射到什么表上,这种情况发生在实体类与数据库表名不一样的时候

public @interface TableName {
    String value() default "";

    String resultMap() default "";
}
1
2
3
4
5

这里有一个深坑,就是 mp 的类型转换器和 autoResultMap 之间需要保存一致,具体问题如下:

使用以下写法,类型转换器才会生效,如果没有指定 autoResultMap,则该字段默认为 false,不会生成带有转换器的 resultMap,但是在数据存入数据库的时候,类型转换器还是会生效。这个是在开发过程中踩过坑的

@TableName(value = "config_entity", autoResultMap = true)
public class ConfigEntity {
    @TableField(typeHandler = JsonArrayStringTypeHandler.class)
    private List<String> testConfig;
}
1
2
3
4
5

该注解对应了 XML 中写法为

<result column="test_config" jdbcType="VARCHAR" property="testConfig" typeHandler="JsonArrayStringTypeHandler" />
1

# 自动填充、别名处理、类型转换 @TableField

如果属性与不一致也会出现问题,在实体类的属性名上使用 @TableFiled 处理不一致问题

通过 MP 自动填充功能,在未设定属性时根据自定义策略自动填充属性并记录到数据库,以下是一个自动填充更新和创建时间的例子

在 POJO 中属性上加入注解 TableField

	//增加时填充
    @TableField(fill = FieldFill.INSERT)
    //修改时填充
    @TableField(fill = FieldFill.UPDATE)
1
2
3
4

创建实现类自定义策略,createTime、updateTime 是指 POJO 中的属性

@Component
class MyHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime", new Date(), metaObject);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

# 逻辑删除 @TableLogic

同时,还有一个非常重要的业务功能——逻辑删除,在被其他业务重度依赖的情况下删除某个数据是非常危险的,需要级联删除其他大量的数据,因此一般使用逻辑删除。该功能使用 @TableLogic 实现,在某个属性实现该注解后,所有的删除功能都会被封装为修改功能,所有的查询功能会自动加入是否被逻辑删除的校验

    @TableLogic(value = "status", delval = "1")
    private Integer status;
1
2

删除时直接调用 mybatis-plus 的删除方法即可

# 通用枚举 @EnumValue

在枚举中添加注解 @EnumValue,使用 MP 进行数据库输入输出时会自动将枚举转换为被标记的值,以及自动将被标记的值转换为枚举

public enum GradeEnum {
	//
    PRIMARY(1, "小学"),  SECONDORY(2, "中学"),  HIGH(3, "高中");

    @EnumValue//标记数据库存的值是code
    private final int code;
    //......
}
1
2
3
4
5
6
7
8

同时还有防止一些注解失效的情况,如果在 SpringBoot 中使用 MP 会配置默认的路径,但是多少可能出现没有扫描到使得注解失效的情况,因此需要在配置文件中手动配置修改 MybatisPlusAutoConfiguration 中的默认值,虽然从 3.5.2 版本开始无需配置,但是大多还是使用以前版本的

mybatis-plus:
    typeEnumsPackage: com.baomidou.springboot.entity.enums
1
2

# 插件

# 分页插件

在配置类中添加分页插件,该插件也比较容易理解。MybatisPlusInterceptor 是 MP 的插件主体,你可以使用 addInnerInterceptor 方法插进去一些功能。而 PaginationInnerInterceptor 就是 MP 已经实现的分页处理,传入的值就是什么数据库。依据传入的值不同,分页的底层实现也不同

@Configuration
public class MyBatisPlusConfig {
    /**  分页插件 */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}
1
2
3
4
5
6
7
8
9
10

不配这个 page 方法用不了(就算使用了,也不会生成 limit 语句),配置了直接使用带有 page 的方法进行查询就可以自动分页,查询的结果会封装到 page 对象中

        Page<Teacher> page = new Page<>(1, 3);
        teacherDao.selectPage(page, null);
        System.out.println(page.getCurrent());//输出当前页
        System.out.println(page.getRecords());//输出查询数据
        System.out.println(page.getPages());//输出总页数
1
2
3
4
5

关于 page 对象,current 就是当前页面数,size 就是每一页多少数据,里面还有个 list 集合 records,里面存放了所有的查询出来的数据

MP 底层使用 limit,并且 page 的设置条件不同与 limit

page 的第一个参数传入需要查询的页数,第二个参数传入查询数量。而 limit 的第一个参数表示从这个数字开始(起始是0),第二个参数传入查询数量

# 乐观锁(Version)

在配置类中增加插件

    /**  乐观锁插件  */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
1
2
3
4
5
6
7

POJO 中的属性添加 Version 注解,这个属性和数据库中对应的字段会成为乐观锁的版本标准。每次进行更新操作,会将该字段加一。大部分使用到这个的场景都可以用分布式锁解决

@Version
private Integer version;
1
2

# 条件构造器

MP 的扩展与插件实现了 mybatis 的拦截器与插件功能,而条件构造器配合提供的各种方法可以实现动态 sql 功能,使用 wrapper 以实现复杂查询 在这里插入图片描述 首先,QueryWrapper 构造了查询条件,里面的方法包含了几乎所有的 sql 语句,比如 eq、le 等,非常好理解,注意传入条件之前一定要把实体类传进去

        new QueryWrapper<User>().eq("user_id", 1);
1

多个条件默认用 and 连接,显示使用 or 方法可以用 or 连接

有些方法可以使用 lambda 表达式构造条件,这些在 lambda 里的条件会优先构造

        new QueryWrapper<User>().eq("user_id", 1).and(i -> i.like("sex", 1));
1

if 标签:有些方法只有在条件满足的时候才会传入条件进去,类似动态sql 的 if 标签

        new QueryWrapper<User>().eq(user.getId() != null, "user_id", 1);
1

查询一个参数:默认会查询所有的数据,可以使用 select 方法指定要查询什么列

        new QueryWrapper<User>().select("name", "id");
1

updateWrapper 的 set 方法:使用 set 方法,在代码中就不用生成实体类了

        wrapper.set("user_id", 4).eq("user_id", 3);
        userDao.update(null, wrapper);
1
2

lambda 化的条件构造器:将传入的参数变成了 lambda,进一步简化了代码

        new LambdaQueryWrapper<User>().eq(User::getUserId, "id");
1

MP 本身是不支持多表联查的,一般项目中也不要使用多表联查,根据经验来说,多表联查的性能远低于查单表

# 代码生成器

这个是最不实用的一个功能也是最难用的一个功能,完全可以使用 EasyCode 代替,使用代码生成器首先需要导入 maven 依赖

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity-engine-core</artifactId>
            <version>2.3</version>
        </dependency>
1
2
3
4
5
6
7
8
9
10

然后在 test 中写生成器代码

    @Test
    void contextLoads() {
        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");//目录名字
        gc.setOutputDir("D:\\IDEAworkspace\\course_work" + "/src/main/java");
        gc.setAuthor("xie13");
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setFileOverride(false); //重新生成时文件是否覆盖
        gc.setServiceName("%sService"); //去掉Service接口的首字母I
        gc.setIdType(IdType.ASSIGN_ID); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式
        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/student");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("123456");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("teacherService");//模块名
        pc.setParent("com.myself.course_work");//包名
        pc.setController("controller");
        pc.setEntity("pojo");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("teacher", "sc", "student", "course");//数据库中的表
        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true)setter链式操作
        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符
        mpg.setStrategy(strategy);

        // 6、执行
        mpg.execute();
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#MybatisPlus
最后更新: 2/23/2026, 9:23:04 AM
MyBatis 重要知识点总结
Spring 框架基础使用

← MyBatis 重要知识点总结 Spring 框架基础使用→

最近更新
01
vibe coding 最佳实践
02-24
02
立直麻将牌效益理论
02-23
03
伪静态是什么
02-08
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式