从BaseMapper到LambdaWrapper:MyBatis-Plus的封神之路

一、MyBatis-Plus简介

1.1、介绍

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生,官网地址:https://baomidou.com/

1.2、特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

1.3、支持数据库

任何能使用 MyBatis 进行增删改查,并且支持标准 SQL 的数据库应该都在 MyBatis-Plus 的支持范围内

1.4、框架结构

二、MyBatis-Plus快速上手

2.1、数据准备

此处依旧采用前篇我们已有的数据库用户表(创建表的SQL语句见前篇):

2.2、项目配置

创建springboot项目,添加如图所示的依赖即可:

maven中根据 spring boot 的版本添加依赖:

Spring Boot 3:

XML 复制代码
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.5</version>
        </dependency>

Spring Boot 2:

XML 复制代码
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.7</version>
</dependency>

配置数据库:

XML 复制代码
# 数据库连接配置
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

2.3、创建实体类

创建实体类UserInfo

java 复制代码
@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接口类

进入BaseMapper类查看源码:

java 复制代码
public interface BaseMapper<T> extends Mapper<T> {
    int insert(T entity);

    int deleteById(Serializable id);

    int deleteById(T entity);
    
    ...
}

该类接收一个泛型参数作为操作对象,因此需要将UserInfo 传入BaseMapper 的**<>**括号中

MyBatis-Plus 提供了基础的 BaseMapper 接口,该接口已实现单表 CRUD 操作。我们只需让自定义的 Mapper 继承 BaseMapper,即可直接使用这些基础功能,无需自行实现单表增删改查操作

2.4、单元测试(CRUD)

java 复制代码
@SpringBootTest
public class MyBatisplusTests {
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Test
    void testSelectByIds(){
        List<UserInfo> list=userInfoMapper.selectBatchIds(List.of(10,11,12));
        list.forEach(System.out::println);
    }

    @Test
    void testInsert(){
        UserInfo userInfo=new UserInfo();
        userInfo.setId(15);
        userInfo.setAge(35);
        userInfo.setPassword("123456");
        userInfo.setGender(1);
        userInfo.setUsername("程序员");
        userInfo.setPhone("10010010011");
        userInfoMapper.insert(userInfo);
    }

    @Test
    void testUpdate(){
        UserInfo userInfo=new UserInfo();
        userInfo.setId(13);
        userInfo.setPhone("20022002200");
        userInfoMapper.updateById(userInfo);
    }
}

运行结果;

三、MyBatis-Plus复杂操作

3.1、主要注解

UserInfoMapper 继承 BaseMapper 时需指定泛型类型 ,这里的 UserInfo 就是与数据库表对应的实体类,MyBatis-Plus 会根据该实体类自动推断表结构信息

默认映射规则如下:

  1. 表名:将实体类的驼峰命名转换为下划线命名(如 UserInfo → user_info)
  2. 字段:将属性名的驼峰命名转换为下划线命名(如 deleteFlag → delete_flag)
  3. 主键:默认使用 id 字段

若实体类与数据库表结构不符合上述默认规则,MyBatis-Plus 提供了多种注解来显式指定映射关系:

3.1.1、@TableName

那么我们根据上述规则进行修改实体类的名称:UserInfo -> Userinfo ,再次执行查询操作:

这种情况我们就可以通过**@TableName注解来标识实体类对应的表**:

3.1.2、@TableField

@TableName注解来标识实体类对应的表,那么@TableField这个注解就是用来标识属性对应的字段名

3.1.3、@TableId

@TableId注解用来指定属性对应的主键

当属性名与数据库字段名不一致时,需在@TableId 注解中明确指定对应字段名;若两者一致,则直接使用@TableId 注解即可

3.2、配置日志

XML 复制代码
mybatis-plus:
  configuration: # 配置打印 MyBatis⽇志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3.3、条件构造器

MyBatis-Plus也提供了强大的条件构造器(Wrapper )来支持复杂查询场景。这套Wrapper机制允许开发者通过链式调用方式构建查询条件,既能提升开发效率,又能有效避免SQL注入风险

条件构造器😄MyBatis-Plus提供的主要Wrapper类及其功能包括:

  1. AbstractWrapper:所有Wrapper类的基类,封装了通用的查询条件构建方法
  2. QueryWrapper:专用于查询条件的构造,在AbstractWrapper基础上扩展了select方法用于指定查询字段
  3. UpdateWrapper:用于构建更新操作的条件
  4. LambdaQueryWrapper:基于Lambda表达式的查询构造器,通过实体类属性引用避免字段名硬编码
  5. LambdaUpdateWrapper:基于Lambda表达式的更新构造器,同样避免字段名硬编码问题
3.3.1、QueryWrapper

QueryWrapper不仅适用于查询语句,还可用于构建修改、删除等操作的查询条件

java 复制代码
    @Test
    void testQueryWrapper(){
        QueryWrapper<Userinfo> queryWrapper=new QueryWrapper<Userinfo>()
                .select("id","username","age","phone")
                .eq("age",18)
                .like("phone","19");
        List<Userinfo> list=userInfoMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }

请注意:

默认情况下,Mybatis-Plus会根据@TableField 注解自动生成字段别名。但如果指定了QueryWrapper的 select 属性,查询结果将仅包含属性值而丢失别名,导致结果映射失败

正常查询:

java 复制代码
    @Test
    void testQueryWrapper2(){
        QueryWrapper<Userinfo> wrapper = new QueryWrapper<>();
        List<Userinfo> users = userInfoMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

指定select时:

java 复制代码
    @Test
    void testQueryWrapper2(){
        QueryWrapper<Userinfo> wrapper = new QueryWrapper<>();
        wrapper.select("create_time"); // 明确指定查询字段
        List<Userinfo> users = userInfoMapper.selectList(wrapper);
        users.forEach(System.out::println);
    }

查询仅包含 create_time 字段,但返回类型为 UserInfo,导致打印结果中其他属性值均为 null

解决方案:

  1. 手动编写自定义SQL
  2. 确保实体类属性名与数据库列名完全一致
  3. 避免在QueryWrapper中显式指定select 字段
  4. 改用LambdaQueryWrapper进行查询

java 复制代码
    @Test
    void testQueryWrapper3(){
        QueryWrapper<Userinfo> wrapper = new QueryWrapper<Userinfo>()
                .lt("age",16);
        Userinfo userinfo=new Userinfo();
        userinfo.setPhone("00000000000");
        userInfoMapper.update(userinfo,wrapper);
    }
  • lt - "less than" 的缩写,表示"小于"
  • le - "less than or equal to" 的缩写,表示"小于等于"
  • ge - "greater than or equal to" 的缩写,表示"大于等于"
  • gt - "greater than" 的缩写,表示"大于"
  • eq - "equals" 的缩写,表示"等于"
  • ne - "not equals" 的缩写,表示"不等于"

java 复制代码
    @Test
    void testQueryWrapper4(){
        QueryWrapper<Userinfo> wrapper = new QueryWrapper<Userinfo>()
                .eq("delete_flag",1);
        userInfoMapper.delete(wrapper);
    }
3.3.2、UpdateWrapper

我们可以直接使用 UpdateWrapper 进行更新操作,无需创建实体对象即可直接设置更新字段和条件

基础更新:

java 复制代码
    @Test
    void testUpdateByUpdateWrapper(){
        UpdateWrapper<Userinfo> updateWrapper = new UpdateWrapper<Userinfo>()
                .set("delete_flag",0)
                .set("age", 5)
                .in("id", List.of(1,2,3));
        userInfoMapper.update(updateWrapper);
    }

基于SQL更新:

java 复制代码
    @Test
    void testUpdateBySQLUpdateWrapper(){
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>()
                .setSql("age = age+10")
                .in("id", List.of(1,2,3));
        userInfoMapper.update(updateWrapper);
    }
3.3.3、LambdaQueryWrapper

使用QueryWrapperUpdateWrapper时存在一个明显问题:需要手动编写字段名称字符串。如果数据库字段名称发生变更,由于测试覆盖不足,很容易引发生产事故

MyBatis-Plus提供了基于Lambda 表达式的条件构造器解决方案,通过Lambda 表达式引用实体类属性,完美解决了字段名硬编码问题。这种方式不仅提升了代码可读性,也显著增强了代码的可维护性

主要实现类包括:

  • LambdaQueryWrapper
  • LambdaUpdateWrapper

这两个类分别对应传统的QueryWrapperUpdateWrapper功能

java 复制代码
    @Test
    void testQueryWrapper5(){
        QueryWrapper<Userinfo> queryWrapper=new QueryWrapper<Userinfo>();
        queryWrapper.lambda().select(Userinfo::getId , Userinfo::getAge,
                Userinfo::getUsername , Userinfo::getPhone)
                .eq(Userinfo::getAge,18)
                .like(Userinfo::getPhone,"19");
        List<Userinfo> list=userInfoMapper.selectList(queryWrapper);
        list.forEach(System.out::println);
    }
3.3.4、LambdaUpdateWrapper
java 复制代码
    @Test
    void testLambdUpdateByUpdateWrapper(){
        UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>();
        updateWrapper.lambda()
                .set(UserInfo::getDeleteFlag, 0)
                .set(UserInfo::getAge, 5)
                .in(UserInfo::getUserId, List.of(1,2,3));
        userInfoMapper.update(updateWrapper);
    }

or 方法是 MyBatis-Plus 提供的核心查询构造方法之一,主要用于实现 OR 逻辑查询条件。该方法会改变后续查询条件的连接方式,将默认的 AND 连接转换为 OR 连接

3.4、自定义SQL

当MyBatis-Plus提供的标准操作无法满足我们的需求时,我们可以利用其提供的自定义SQL功能;通过Wrapper构建查询条件,再配合Mapper编写SQL语句,就能灵活实现各种复杂查询需求

java 复制代码
---------------mapper------------------
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
    @Select("select id,username,password,age FROM user_info ${ew.customSqlSegment}")
    List<UserInfo> queryUserByCustom(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);
}
---------------test--------------------
@Test
void testQueryUserByCustom(){
    QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>()
        .eq("username","admin");
    userInfoMapper.queryUserByCustom(queryWrapper).forEach(System.out::println);
}

注意事项:

  • 参数命名 :在自定义 SQL 时,若需传递 Wrapper 对象作为参数,必须使用 ew 作为参数名,或者通过 @Param(Constants.WRAPPER) 注解明确指定该参数为 Wrapper 对象
  • 使用方式 :在 SQL 语句中,通过 ${ew.customSqlSegment} 来引用 Wrapper 对象生成的 SQL 片段
  • 功能限制:使用自定义 SQL 时,Wrapper 对象不会基于实体类自动生成 where 子句,需要手动编写完整的 SQL 语句
相关推荐
青云交2 小时前
Java 大视界 -- Java 大数据机器学习模型在元宇宙虚拟场景智能交互中的关键技术
java·机器学习·边缘计算·元宇宙·多模态融合·智能交互·情感计算
老任与码3 小时前
责任链模式
java·开发语言·责任链模式
哇!好大一个橙子3 小时前
Google浏览器及其对应版本chromedriver驱动下载(含最新版本)
java·python
安然~~~3 小时前
jvm之【垃圾回收器】
java·jvm
不宕机的小马达3 小时前
【Maven】Maven概述、安装以及其他相关知识
java·数据库·maven
鸽鸽程序猿3 小时前
【算法】【优选算法】BFS 解决边权相同最短路问题
java·算法·宽度优先
xiyangxiaoguo3 小时前
Qt QEventLoop的使用的一个问题讨论
java·前端·算法
卷Java3 小时前
百度智能云车牌识别API官方配置指南
java·开发语言·经验分享·vscode·学习·微信小程序·intellij idea
你的微笑,乱了夏天3 小时前
spring boot项目使用Torna生成在线接口文档
java·spring boot·中间件·postman
小信丶3 小时前
Spring Boot启动报错:Failed to configure a DataSource 全面解析与解决方案
spring boot·后端·mybatis