news 2026/4/17 13:39:31

MyBatisPlus(MP)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MyBatisPlus(MP)

MyBatisPlus(MP)

鸣谢:黑马程序员。(视频链接:【黑马程序员SSM框架教程_Spring+SpringMVC+Maven高级+SpringBoot+MyBatisPlus企业实用开发技术】https://www.bilibili.com/video/BV1Fi4y1S7ix?vd_source=b7f14ba5e783353d06a99352d23ebca9)

文章目录

  • MyBatisPlus(MP)
    • 一、入门
      • 1.入门案例
      • 2.概述
    • 二、标准数据层开发
      • 1.标准CRUD开发
        • 1.1 MP接口
        • 1.2 代码示例
      • 2.分页功能
        • 2.1 配置MP拦截器类,添加MP的分页拦截器
        • 2.2 在`application.yml`中开启MP的控制台日志
        • 2.3 执行分页查询
        • 2.4 运行结果
    • 三、条件查询
      • 1.条件查询方式
        • 1.1 单条件查询
        • 1.2 多条件查询(支持链式编程)
        • 1.3 NULL值处理
      • 2.查询投影
        • 2.1 查询结果包含实体类中部分属性
        • 2.2 查询结果包含聚合函数
        • 2.3 假如2.2不用MP,而用MyBatis+原生SQL
      • 3.查询条件设定
      • 4.字段映射与表名映射——`@TableField`+`@TableName`
          • 4.1 表字段与实体类属性设计不同步
        • 4.2 实体类中添加了表中未定义的字段
        • 4.3 采用`select *`查询开放了过多的字段查看权限,存在安全隐患
        • 4.4 表名与实体类名设计不同步
    • 四、DML控制
      • 1.ID生成策略控制
        • 1.1 `@TableId`
        • 1.2 ID生成策略
      • 2.多记录删除
      • 3.逻辑删除
        • 3.1 业务场景
        • 3.2 普通删除 VS 逻辑删除
        • 3.3 实现步骤
      • 4.乐观锁(并发访问)
    • 五、快速开发——代码生成器

一、入门

1.入门案例

  1. 创建新模块,选择SpringBoot,并配置模块相关基础信息。

  2. 选择当前模块需要使用的技术栈,仅勾选MySQL Driver

  3. 手动添加MP和Druid的起步依赖:

    <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><!-- 使用与SpringBoot3.5.9版本兼容的MP版本 --><version>3.5.11</version><!-- 示例版本 --></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-jsqlparser</artifactId><version>3.5.11</version><!-- 必须与上面的版本保持一致 --></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.23</version><!-- 确保支持Spring3.5.9 --></dependency>
  4. application.yml文件中设置数据源:

    spring:datasource:type:com.alibaba.druid.pool.DruidDataSourcedriver-class-name:com.mysql.cj.jdbc.Driverurl:jdbc:mysql://localhost:3306/mybatis_plus_dbusername:rootpassword:123456
  5. 根据数据库中要操作的表结构制作实体类User:类名与表名对应,属性名与字段名对应。

  6. 定义dao接口,继承BaseMapper<User>

    @MapperpublicinterfaceUserDaoextendsBaseMapper<User>{}
  7. 在测试类中注入dao接口,测试功能:

    @SpringBootTestclassApplicationTests{@AutowiredprivateUserDaouserDao;@TestvoidtestGetAll(){List<User>users=userDao.selectList(null);System.out.println(users);}}

2.概述

  • MyBatisPlus(简称MP)是基于MyBatis框架开发的增强型工具,旨在简化开发、提高效率。

  • 官网:https://baomidou.com或https://mybatis.plus

  • 特性

    • 无侵入:只做增强不做修改,不会对原有工程产生影响。
    • 损耗小:启动即会自动注入基本CRUD,性能基本无损耗,直接面向对象操作。
    • 强大的CRUD操作:内置通用Mapper和通用Service,只需少量手动配置即可实现单表大部分CRUD操作。
    • 支持Lambda:编写查询条件时,无需担心字段写错。
    • 支持主键自动生成。
    • 内置分页插件。
    • ……


二、标准数据层开发

1.标准CRUD开发

1.1 MP接口
功能MP接口
新增int insert(T t)
删除int deleteById(Serializable id)
修改int updateById(T t)
根据id查询T selectById(Serializable id)
查询全部List<T> selectList()
分页查询IPage<T> selectPage(IPage<T> page)
条件查询IPage<T> selectPage(Wrapper<T> queryWrapper)
1.2 代码示例
@SpringBootTestclassMp01QuickstartApplicationTests{@AutowiredprivateUserDaouserDao;@TestvoidtestInsert(){Useruser=newUser("zsh","666999",18,"842951084");userDao.insert(user);}@TestvoidtestDelete(){userDao.deleteById(2006633799126016002L);}@TestvoidtestUpdate(){Useruser=newUser();user.setId(1L);user.setName("Tommy");// 提供哪些字段的新值,MP就只会修改这些字段userDao.updateById(user);}@TestvoidtestGetById(){Useruser=userDao.selectById(2L);System.out.println(user);}@TestvoidtestGetAll(){List<User>users=userDao.selectList(null);System.out.println(users);}}

2.分页功能

2.1 配置MP拦截器类,添加MP的分页拦截器
packagecom.zsh.config;importcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;// 配置MP的拦截器@ConfigurationpublicclassMpConfig{@BeanpublicMybatisPlusInterceptormpInterceptor(){MybatisPlusInterceptormpInterceptor=newMybatisPlusInterceptor();// 添加MP的分页拦截器mpInterceptor.addInnerInterceptor(newPaginationInnerInterceptor());returnmpInterceptor;}}
2.2 在application.yml中开启MP的控制台日志
# 开启MP的控制台日志mybatis-plus:configuration:log-impl:org.apache.ibatis.logging.stdout.StdOutImpl
2.3 执行分页查询
@TestvoidtestGetByPage(){// 首先要配置好MP的分页拦截器——config/MpConfigIPagepage=newPage(2,3);// 查第2页,每页显示3条记录userDao.selectPage(page,null);System.out.println("当前页码值: "+page.getCurrent());System.out.println("每页记录数: "+page.getSize());System.out.println("总页数: "+page.getPages());System.out.println("总记录数: "+page.getTotal());System.out.println("page data: "+page.getRecords());}
2.4 运行结果



三、条件查询

1.条件查询方式

1.1 单条件查询
@SpringBootTestclassMp02ConditionQueryApplicationTests{@AutowiredprivateUserDaouserDao;@Testvoidtest1(){// 方式一:按条件查询QueryWrapperqw=newQueryWrapper();qw.lt("age",18);List<User>users=userDao.selectList(qw);System.out.println(users);}@Testvoidtest2(){// 方式二:Lambda格式的按条件查询,可以防止字段名写错QueryWrapper<User>qw=newQueryWrapper<>();qw.lambda().lt(User::getAge,10);List<User>users=userDao.selectList(qw);System.out.println(users);}@Testvoidtest3(){// 方式三:Lambda格式的按条件查询——简化版LambdaQueryWrapper<User>lqw=newLambdaQueryWrapper<>();lqw.ge(User::getAge,25);List<User>users=userDao.selectList(lqw);System.out.println(users);}}
1.2 多条件查询(支持链式编程)
@Testvoidtest4(){LambdaQueryWrapper<User>lqw=newLambdaQueryWrapper<>();// age>18 && age<22// lqw.gt(User::getAge,18).lt(User::getAge,22);// age<10 || age>30lqw.lt(User::getAge,10).or().gt(User::getAge,30);List<User>users=userDao.selectList(lqw);System.out.println(users);}
1.3 NULL值处理

为什么要处理null值?来看下面的业务场景:

前端页面提示用户输入目标商品的下限价格和上限价格,但有些情况下用户可能只输入下限值或上限值或两个都不输入,这样就会导致前端传到后端的上限值或下限值为null,这时候就需要对这些null值做处理。

@Testvoidtest5(){// 模拟前端页面传递过来的查询数据UserQueryuserQuery=newUserQuery();userQuery.setAge(18);userQuery.setMaxAge(22);// null值处理LambdaQueryWrapper<User>lqw=newLambdaQueryWrapper<>();/* 先判断第一个入参是否为true,如果为true就连接当前条件 等价于: if (userQuery.getAge() != null) { lqw.gt(User::getAge, userQuery.getMaxAge()); } */lqw.gt(userQuery.getAge()!=null,User::getAge,userQuery.getAge());lqw.lt(userQuery.getMaxAge()!=null,User::getAge,userQuery.getMaxAge());List<User>users=userDao.selectList(lqw);System.out.println(users);}

2.查询投影

[!Tip]

从查询结果中筛选并展示指定列(字段)的过程。

2.1 查询结果包含实体类中部分属性
@Test// 查询投影voidtest6(){LambdaQueryWrapper<User>lqw=newLambdaQueryWrapper<>();lqw.select(User::getId,User::getName,User::getAge);List<User>users=userDao.selectList(lqw);System.out.println(users);}
2.2 查询结果包含聚合函数
@Testvoidtest7(){QueryWrapper<User>lqw=newQueryWrapper<>();lqw.select("count(*) as count, tel");lqw.groupBy("tel");List<Map<String,Object>>users=userDao.selectMaps(lqw);System.out.println(users);}
2.3 假如2.2不用MP,而用MyBatis+原生SQL

首先在UserDao接口中编写getTelGroup()这个接口方法:

@MapperpublicinterfaceUserDaoextendsBaseMapper<User>{@Select("select count(*) as count, tel from user group by tel")List<Map<String,User>>getTelGroup();}

其次在测试类中编写测试方法:

@Testvoidtest7Plus(){List<Map<String,User>>telGroup=userDao.getTelGroup();System.out.println(telGroup);}

可以看到,对于复杂、固定的查询,尤其涉及多表连接和复杂聚合时,使用MyBatis编写原生SQL可能是更好的选择。


3.查询条件设定

函数名作用等效SQL片段
eq(R column, Object val)等于(=)id = 10
ne(R column, Object val)不等于(<>)name <> '张三'
gt(R column, Object val)大于(>)age > 18
ge(R column, Object val)大于等于(>=)age >= 18
lt(R column, Object val)小于(<)age < 30
le(R column, Object val)小于等于(<=)age <= 30
between(R column, Object val1, Object val2)区间匹配age between 18 and 30
like(R column, Object val)模糊匹配name like '%张%'
likeLeft(R column, Object val)左模糊匹配name like '%三'
likeRight(R column, Object val)右模糊匹配name like '张%'
isNull(R column)字段为空email is null
isNotNull(R column)字段不为空email IS not nu;;
orderByAsc(R... columns)升序排序(ORDER BY column ASC)order by age ASC, id ASC
orderByDesc(R... columns)降序排序(ORDER BY column DESC)order by age DESC, id DESC

4.字段映射与表名映射——@TableField+@TableName

4.1 表字段与实体类属性设计不同步

解决方案:使用@TableField注解将实体类属性与表字段关联起来。

publicclassUser{@TableField(value="pwd")privateStringpassword;}
4.2 实体类中添加了表中未定义的字段

解决方案:使用@TableField注解表明该属性在表中没有对应字段。

publicclassUser{@TableField(exist=false)privateIntegeronline;}

注意exist无法与value同时使用。

4.3 采用select *查询开放了过多的字段查看权限,存在安全隐患

解决方案:使用@TableField注解设置某个表字段不可查询。

publicclassUser{@TableField(value="pwd",select=false)privateStringpassword;}
4.4 表名与实体类名设计不同步

解决方案:使用@TableName注解将实体类与表关联起来。

@TableName("tbl_user")publicclassUser{...}


四、DML控制

1.ID生成策略控制

1.1@TableId

@TableId注解是一种属性注解,位于实体类中用于表示主键的属性上方,可以设置当前类中主键属性的生成策略。示例如下:

publicclassUser{@TableId(type=IdType.AUTO)privateLongid;}

该注解的相关属性主要有2个:

  • value:设置表主键名称。
  • type:设置当前类中主键属性的生成策略,值参照IdType枚举值。
1.2 ID生成策略
策略值策略名称说明
0AUTO使用数据库id自增策略控制id生成
1NONE不设置id生成策略
2INPUT用户手动输入id
3ASSIGN_ID雪花算法生成id(可兼容数值型与字符串型)
4ASSIGN_UUIDUUID算法生成id生成

2.多记录删除

@TestvoidtestDelete(){List<Long>ids=newArrayList<>();ids.add(7L);ids.add(8L);ids.add(9L);userDao.deleteByIds(ids);}

3.逻辑删除

3.1 业务场景

现在员工张业绩已经离职,数据库会删除他的相关记录:

然而年底统计总业绩时却出现了漏洞:明显小于实际总业绩。

3.2 普通删除 VS 逻辑删除
  • 普通删除:将相关业务记录直接从数据库中丢弃。
  • 逻辑删除:为业务记录设置一个字段“是否处于可用状态”,删除时设置该字段为“不可用状态”,记录仍保留在数据库中。此字段称为“逻辑删除字段”。
3.3 实现步骤
  1. 数据库对应表中添加逻辑删除字段deleted,默认值为0。

  2. 实体类中添加对应属性,并使用@TableLogic注解标记其为逻辑删除属性。

    publicclassUser{@TableLogicprivateIntegerdeleted;}
  3. 之后MP查询时会自动带上条件where deleted=0,忽略标记为“已删除”的记录。


4.乐观锁(并发访问)

[!Tip]

乐观锁机制下,每次修改都会执行version++操作,只有当version等于特定值时才允许线程执行修改操作。

  1. 数据库对应表中添加乐观锁字段version,默认值为1。

  2. 实体类中添加对应属性,并使用@Version注解标记其为乐观锁属性。

    publicclassUser{@VersionprivateIntegerversion;}
  3. 配置乐观锁拦截器,实现锁机制对应的动态SQL语句拼接。

    packagecom.zsh.config;importcom.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;importcom.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;// 配置MP的拦截器@ConfigurationpublicclassMpConfig{@BeanpublicMybatisPlusInterceptormpInterceptor(){MybatisPlusInterceptormpInterceptor=newMybatisPlusInterceptor();// 添加MP的乐观锁拦截器mpInterceptor.addInnerInterceptor(newOptimisticLockerInnerInterceptor());returnmpInterceptor;}}
  4. 若使用乐观锁机制,在修改记录前必须先获取到该记录的version,然后才能正常执行。



五、快速开发——代码生成器

[!Tip]

个人觉得这个东西了解即可,现在完全可以由AI大模型负责该工作。

  • 模板:MyBatisPlus提供。
  • 数据库相关配置:读取数据库获取信息。
  • 开发者自定义配置:手动配置。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 9:57:01

英雄联盟辅助工具LeagueAkari:5步实现游戏自动化的完整指南

英雄联盟辅助工具LeagueAkari&#xff1a;5步实现游戏自动化的完整指南 【免费下载链接】LeagueAkari ✨兴趣使然的&#xff0c;功能全面的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/LeagueAkari Lea…

作者头像 李华
网站建设 2026/4/18 3:35:40

小米运动自动刷步数2025:5分钟搞定多平台同步完整指南

小米运动自动刷步数2025&#xff1a;5分钟搞定多平台同步完整指南 【免费下载链接】mimotion 小米运动刷步数&#xff08;微信支付宝&#xff09;支持邮箱登录 项目地址: https://gitcode.com/gh_mirrors/mimo/mimotion 小米运动自动刷步数工具是一款专为Zepp Life用户设…

作者头像 李华
网站建设 2026/4/17 14:30:25

纪念币预约自动化终极指南:告别手忙脚乱的智能预约方案

纪念币预约自动化终极指南&#xff1a;告别手忙脚乱的智能预约方案 【免费下载链接】auto_commemorative_coin_booking 项目地址: https://gitcode.com/gh_mirrors/au/auto_commemorative_coin_booking 还在为每次纪念币预约时的手忙脚乱而烦恼吗&#xff1f;纪念币预约…

作者头像 李华
网站建设 2026/4/18 3:36:26

如何快速实现微信多设备登录:终极完整教程

如何快速实现微信多设备登录&#xff1a;终极完整教程 【免费下载链接】WeChatPad 强制使用微信平板模式 项目地址: https://gitcode.com/gh_mirrors/we/WeChatPad 还在为微信只能在一台设备登录而烦恼吗&#xff1f;WeChatPad开源项目为你提供了完美的解决方案。这个强…

作者头像 李华
网站建设 2026/4/9 11:51:06

MMD Tools插件完整安装指南:让MMD模型在Blender中完美运行

MMD Tools插件完整安装指南&#xff1a;让MMD模型在Blender中完美运行 【免费下载链接】blender_mmd_tools MMD Tools is a blender addon for importing/exporting Models and Motions of MikuMikuDance. 项目地址: https://gitcode.com/gh_mirrors/bl/blender_mmd_tools …

作者头像 李华
网站建设 2026/4/16 11:10:39

重构Windows DLL注入:Xenos的5种创新方法完全指南

Xenos DLL注入器作为Windows动态链接库加载的专业工具&#xff0c;彻底改变了传统DLL注入的操作方式。无论你是安全研究人员还是开发工程师&#xff0c;都能通过本指南掌握其核心功能与实战技巧。 【免费下载链接】Xenos Windows dll injector 项目地址: https://gitcode.com…

作者头像 李华