[Mybatis] 超详细 MyBatis-Plus 入门教程

1.MyBatis-Plus 介绍

MyBatis-Plus 是MyBatis 的增强工具 , 在MyBatis 的基础上增强不做改变 , 为简化开发而生 , 提高效率而生 ; 省去大量重复的 XML/注解 SQL

特点 :

  • 自动生成单表查询
  • 强大的条件构造器
  • 支持 Lambda , 分页 , 逻辑删除 , 自动填充
  • 兼容所有 Mybatis 写法

MyBatis-Plus 官网条件构造器

快速上手

1.项目准备

1.1 SQL 准备

sql 复制代码
DROP DATABASE IF EXISTS mybatis_test2;
CREATE DATABASE mybatis_test2 DEFAULT CHARACTER SET utf8mb4;

USE mybatis_test2;

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 user_info(username, password, age, gender, phone)
VALUES
('admin','admin',18,1,'18612340001'),
('zhangsan','zhangsan',18,1,'18612340002'),
('lisi','lisi',18,1,'18612340003'),
('wangwu','wangwu',18,1,'18612340004');

2.2 pom 文件

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>4.0.6</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.boop</groupId>
    <artifactId>Mybatis-Plus</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Mybatis-Plus</name>
    <description>Mybatis-Plus</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webmvc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>4.0.1</version>
        </dependency>

        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webmvc-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter-test</artifactId>
            <version>4.0.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

这四个依赖

MyBatis-Plus 依赖

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

注意引入MyBatis-Plus 时 , Spring 的版本不能过高 , 否则会产生冲突

1.3 配置数据库相关文件

html 复制代码
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mybatis_test2?characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

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

配置数据库 , 打印日志 , 匹配 Mapper.xml 的路径

1.4 创建实体类

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;
}

1.5 编写 Mapper 接口

java 复制代码
@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}

不需要写任何的方法

只需要继承 BaseMapper 接口 , 它已经实现了单表查询的 CRUD , 无需再编写单表 CRUD 代码

2. 测试代码

java 复制代码
package com.boop.mybatisplus.mapper;

import com.boop.mybatisplus.model.UserInfo;
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 MyBatisPlusTest {

    @Autowired
    private UserInfoMapper userInfoMapper;

    // 1. 新增
    @Test
    void testInsert() {
        UserInfo user = new UserInfo();
        user.setUsername("bite");
        user.setPassword("123456");
        user.setAge(11);
        user.setGender(0);
        user.setPhone("18610001234");
        userInfoMapper.insert(user);
    }

    // 2. 根据ID查询
    @Test
    void testSelectById() {
        UserInfo user = userInfoMapper.selectById(1);
        System.out.println(user);
    }

    // 3. 批量ID查询
    @Test
    void testSelectBatchIds() {
        List<UserInfo> users = userInfoMapper.selectBatchIds(List.of(1,2,3,4));
        users.forEach(System.out::println);
    }

    // 4. 根据ID更新
    @Test
    void testUpdateById() {
        UserInfo user = new UserInfo();
        user.setId(1);
        user.setPassword("4444444");
        userInfoMapper.updateById(user);
    }

    // 5. 根据ID删除
    @Test
    void testDeleteById() {
        userInfoMapper.deleteById(5);
    }
}

@SpringBootTest 必须要有 , 否则报空指针

users.forEach(System.out::println)

= users.forEach(user -> System.out.println(user))

= for (UserInfo user : users) { System.out.println(user); }

3.Mybatis-Plus 复杂操作

3.1 常见注解

MyBatis-Plus会根据这个实体类来推断表的信息.

默认情况下:

  1. 表名:实体类的驼峰表示法转换成蛇形表示法,以下划线分割,作为表名。例如 UserInfo 转为 user_info
  2. 字段:根据实体类的属性名转换为蛇形表示法作为字段名。例如 deleteFlag 转为 delete_flag
  3. 主键:默认为 id

当命名不规范时,Mybatis-Plus 提供了能够表示表信息的注解

数据库字段

① @TableName

命名不规范此类名对应的是 userinfo 表名 ; 正确的是 user_info

用注解 @TableName("user_info") 可以标识实体类对应的表名

java 复制代码
@Data
@TableName("user_info")
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;
}

运行程序, 结果正常

java 复制代码
@Test
void testInsert() {
    Userinfo user = new Userinfo();
    user.setUsername("bite");
    user.setPassword("123456");
    user.setAge(11);
    user.setGender(0);
    user.setPhone("18610001234");
    user.setDeleteflag(1);
    userInfoMapper.insert(user);
}

② @TableField

命名不规范此属性对应的字段为 deleteflag ; 正确的是 delete_flage

用@TableField("delete_flag") , 表示属性名对应的字段名

注意 : 演示时注意 Getter(),Setter()方法也要跟着变

java 复制代码
@Data
@TableName("user_info")
public class Userinfo {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    @TableField("delete_flag")
    private Integer deleteflag;
    private Date createTime;
    private Date updateTime;
}

测试代码

java 复制代码
@Test
void testInsert() {
    Userinfo user = new Userinfo();
    user.setUsername("bite");
    user.setPassword("123456");
    user.setAge(11);
    user.setGender(0);
    user.setPhone("18610001234");
    user.setDeleteflag(1);
    userInfoMapper.insert(user);
}

③ @TableId

命名不规范

java 复制代码
@Data
@TableName("user_info")
public class Userinfo {
    @TableId(value = "id", type = IdType.AUTO)
    private Integer userid;
    private String username;
    private String password;
    private Integer age;
    private Integer gender;
    private String phone;
    @TableField("delete_flag")
    private Integer deleteflag;
    private Date createTime;
    private Date updateTime;
}

@TableId(value ="id", type =IdType.AUTO) , 属性名和字段名不一致 , 需要在 注解中表明对应的字段名 (选择性加入自增主键)

如果属性名和字段名一致 , 则直接加@TableId 注解即可

3.2 条件构造器

|-------------------------|--------------------|-----------------------------------------------------------|
| 类名 | 核心用途 | 特点 |
| AbstractWrapper | 所有条件构造器的抽象父类 | 封装了所有通用条件方法(eqnegtltlikein等),是其他 4 个类的基础 |
| QueryWrapper | 构建查询条件(SELECT语句) | 支持链式调用,可指定查询字段、过滤条件、排序、分组等 |
| UpdateWrapper | 构建更新条件(UPDATE语句) | 可同时指定更新字段和更新条件,无需额外创建实体对象 |
| LambdaQueryWrapper | 基于 Lambda 的查询构造器 | 通过 实体类::getter引用字段,避免硬编码字段名,降低写错字段名的风险 |
| LambdaUpdateWrapper | 基于 Lambda 的更新构造器 | 通过 实体类::setter实体类::getter引用字段,避免编码,类型安全 |

① 通用条件方法(所有 Wrapper 通用)

|--------------------------|----------------------------|-------------------------|
| 方法 | 作用 | 对应 SQL |
| eq("name", "张三") | equal 等于 | name = '张三' |
| ne("age", 18) | not equal 不等于 | age <> 18 |
| gt("age", 18) | greater than 大于 | age > 18 |
| lt("age", 18) | less than 小于 | age < 18 |
| ge("age", 18) | greater than or equal 大于等于 | age >= 18 |
| le("age", 18) | less than or equal 小于等于 | age <= 18 |
| like("name", "张") | like 模糊查询 | name LIKE '%张%' |
| in("id", 1,2,3) | IN 查询 | id IN (1,2,3) |
| between("age", 18, 30) | 区间查询 | age BETWEEN 18 AND 30 |
| orderByDesc("age") | 降序排序 | ORDER BY age DESC |
| orderByAsc("age") | 升序排序 | ORDER BY age ASC |

② QueryWrapper 和 LambdaQueryWrapper 示例

java 复制代码
//
@Test
void testQueryWrapper(){

    //使用QueryWrapper
    QueryWrapper<Userinfo> userinfoQueryWrapper = new QueryWrapper<Userinfo>()
            .select("id", "username", "age")
            .eq("age", 18)
            .like("username", "张");

    List<Userinfo> userinfos1 = userInfoMapper.selectList(userinfoQueryWrapper);
    userinfos1.forEach(System.out::println);

    //使用LambdaQueryWrapper (防止字段名硬编码,字段名不会写错)
    LambdaQueryWrapper<Userinfo> userinfoLambdaQueryWrapper = new LambdaQueryWrapper<Userinfo>()
            .select(Userinfo::getUserid,Userinfo::getUsername,Userinfo::getAge)
            .gt(Userinfo::getAge,18)
            .like(Userinfo::getUsername,"张");
    List<Userinfo> userinfos2 = userInfoMapper.selectList(userinfoLambdaQueryWrapper);
    userinfos2.forEach(System.out::println);
}

对应 SQL

sql 复制代码
SELECT userid,username,age 
FROM userinfo 
WHERE age = 18 
AND username 
LIKE '%张%'
sql 复制代码
SELECT userid,username,age 
FROM userinfo 
WHERE age > 18 
AND username 
LIKE '%张%'

注意 :

在变量声明时写了泛型 <Userinfo>,但 new QueryWrapper<>() 时,Java 类型推断没有正确识别泛型类型,而是推断成了 Object,导致前后类型不匹配

③ UpdateWrapper 和 LambdaUpdateWrapper 示例

java 复制代码
// 7. UpdateWrapper  和 LambdaUpdateWrapper 示例
@Test
void testUpdateWrapper(){
    //使用UpdateWrapper
    UpdateWrapper<Userinfo> updateWrapper = new UpdateWrapper<Userinfo>();
    updateWrapper.set("username","张三").set("update_time", LocalDateTime.now())
            .eq("age",18);

    // 第一个参数 null:表示不通过实体类传值,只使用 UpdateWrapper 里的 set 值
    // 第二个参数 updateWrapper:更新的字段 + 条件
    int count1 = userInfoMapper.update(null,updateWrapper);

    //使用LambdaUpdateWrapper
    LambdaUpdateWrapper<Userinfo> userinfoLambdaUpdateWrapper = new LambdaUpdateWrapper<Userinfo>()
            .set(Userinfo::getUsername,"张三")
            .set(Userinfo::getUpdateTime,LocalDateTime.now())
            .eq(Userinfo::getAge,18);
    int count2 = userInfoMapper.update(null,updateWrapper);

}

对应 SQL

sql 复制代码
SELECT id, username, age 
FROM userinfo 
WHERE age = 18 
AND username 
LIKE '%张%'

总结 :

LambdaUpdateWrapper 和 LambdaQueryWrapper 是基于 Lambda 表达式的条件构造器 , 通过 Lambda 表达式来应用实体类的属性 , 从而避免因为命名不规范或字段名不匹配产生的硬编码问题 , 提高了代码的可读性

④ 自定义 SQL(此处演示的为注解+Wrapper)

MyBatis-Plus 提供了自定义 SQL 的功能 , 可以利用 Wrapper 构造查询条件 , 再结合 Wrapper 编写 SQL

注意 :

编写 Mapper

java 复制代码
@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);
}

编写测试代码

java 复制代码
// 8.自定义Mybatis-Plus 的SQL
@Test
void queryUserByCustom(){
    QueryWrapper<Userinfo> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("username","admin");
    userInfoMapper.queryUserByCustom(queryWrapper).forEach(System.out::println);
}

最终 SQL : select id,username,password,age FROM user_info WHERE username = 'admin'

原理 :

  • 必须继承 BaseMapper 通用 CRUD

  • 需要自己写 select....from....部分 , 实现自定义字段 , 多表联查等需求

  • 必须通过{ew.customSqlSegment} 让 Mapper 自动拼接 Wrapper 里的 where 条件 ; 支持所有条件方法 ; **注意是{}**

  • 必须用@Param(Constants.WRAPPER) 作用 : 告诉 Mybatis , 这个是 Wrapper 对象 , 在 SQL 中用${ew.xxx}来引用 (如果不写注解 , 则找不到引用对象)
    注意 :

  • 不要引错包名 , 正确包名 : import com.baomidou.mybatisplus.core.conditions.Wrapper

  • ${ew.xxx}必须写在 from 表名之后

以下均为示例片段 , 没有做准备

支持多表联查(需要配置多表环境)
java 复制代码
@Select("SELECT u.*, d.dept_name " 
+ "FROM user_info u " 
+ "LEFT JOIN dept d ON u.dept_id = d.id " 
+ "${ew.customSqlSegment}") 
List<UserVO> selectUserWithDept(@Param(Constants.WRAPPER)Wrapper<UserInfo> wrapper);
支持 Lambda
java 复制代码
@Test
void testLambdaQuery(){
    LambdaQueryWrapper<UserInfo> wrapper = newLambdaQueryWrapper<>(); 
    wrapper.eq(UserInfo::getUsername,"admin")
    .ge(UserInfo::getAge,18); 
    userInfoMapper.queryUserByCustom(wrapper).forEach(System.out::println);}
支持 Mapper.xml+Wrapper

https://www.yuque.com/u29274559/wwxtlt/hkx9urdliqy551tv

vb 复制代码
`<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPEmapperPUBLIC"-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mappernamespace="com.bite.mybatis.plus.mapper.UserInfoMapper">
    <selectid="queryUserByCustom2"> 
        select id,username,password,age FROM user_info ${ew.customSqlSegment} 
                                                         
    </select>
</mapper>`
相关推荐
Devin~Y3 小时前
大厂Java面试实战:Spring Boot/Cloud、Redis/Kafka、JVM调优与Spring AI RAG(内容社区UGC+AIGC客服场景)
java·jvm·spring boot·redis·spring cloud·kafka·mybatis
Boop_wu4 小时前
[Mybatis] XML 方式实现 MP 自定义 SQL + 条件构造器
xml·sql·mybatis
夕除14 小时前
springboot--06
数据库·spring boot·mybatis
Java成神之路-18 小时前
MyBatis一级缓存与二级缓存深度解析
mybatis
身如柳絮随风扬19 小时前
MyBatis 与 Spring 中的设计模式
spring·设计模式·mybatis
范什么特西1 天前
第一个Mybatis
java·开发语言·mybatis
Java成神之路-1 天前
MyBatis 关联查询的延迟加载与积极加载原理
java·mybatis
Don.TIk1 天前
天机の学堂
java·spring boot·spring·maven·mybatis
Devin~Y1 天前
大厂Java面试实录:Spring Boot/JPA/Redis/Kafka/K8s 可观测性 + Spring AI RAG/Agent(小Y翻车现场)
java·spring boot·redis·mybatis·hibernate·spring mvc·jpa