使用 MyBatis-Plus 快速上手(学习笔记)

导读

本文为个人学习 MyBatis-Plus 的笔记,目标是记录从建表、项目初始化到常用 CRUD、条件构造器与分页插件的使用流程与关键注意点。文章以实用示例为主,保留必要说明,便于复现与回顾。


准备工作:建表与环境

建表 SQL

为练习 MyBatis-Plus,先创建一张测试表 u_user(此处主键非自增):

create table u_user
(
  id    int         not null comment '主键(这里非自增)'
       primary key,
  name  varchar(60) null comment '姓名',
  age   int         null comment '年龄',
  email varchar(80) null comment '邮箱'
)
   comment '学习 MyBatisPlus 而建立的 u_user 表';

说明:示例中把 id 设为非自增,以便演示手动赋值插入;生产环境中根据业务需要决定是否自增或使用雪花/UUID 等主键策略。

项目与依赖

新建 Spring Boot 项目(示例名:mp-01-first),构建工具为 Maven,JDK 21,Spring Boot 3.x(示例使用 3.5.5)。基础依赖至少包含:

  • Lombok(减少样板代码)

  • MySQL 驱动

  • MyBatis-Plus 的 Spring Boot starter(推荐使用 starter)

pom.xml 中加入 MyBatis-Plus starter(必须使用 starter,不要只引入核心包):

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

提示:直接引入 com.baomidou:mybatis-plus 可能不会带上与 Spring Boot 集成所需的类,容易出现 @MapperScan 或 Spring 自动配置不可用的情况。

数据库配置(application.yml)

示例的 application.yml(请替换用户名/密码与数据库名):

spring:
application:
  name: mp-01-first
datasource:
  driver-class-name: com.mysql.cj.jdbc.Driver
  url: jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf8&useSSL=false
  username: root
  password: xxxxxxxxxxxxxxxxxxxxx
  hikari:
    maximum-pool-size: 10
    minimum-idle: 2
    max-lifetime: 60000
    connection-test-query: select 1

# mapper xml 的位置(mybatis-plus 推荐配置前缀)
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
configuration:
  log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

说明:mapper-locations 可放在 mybatismybatis-plus 下,但推荐使用 mybatis-plus 的配置前缀以保持一致。同时 log-impl 可用于在控制台输出 SQL,便于调试。


实体映射(Entity)

示例实体类 User

package com.sangui.domain;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
* @Author: sangui
* @CreateTime: 2025-08-26
* @Description: user 实体类
* @Version: 1.0
*/
@Data
@TableName("u_user")
public class User {
   @TableId("id")
   private Integer id;

   @TableField("name")
   private String name;

   @TableField("age")
   private Integer age;

   @TableField("email")
   private String email;
}
  • @TableName:当类名与表名不一致时使用(示例中类名 User 与表 u_user 不同)。

  • @TableId:标注主键列(如果列名为 id 且默认策略可接受,可省略)。

  • @TableField:当字段名与列名一致时通常 可省略;示例为清晰起见显式标注。


Mapper 接口与 @MapperScan

创建 Mapper 接口并继承 BaseMapper<T>,即可获得单表 CRUD 的方法:

package com.sangui.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.sangui.domain.User;

public interface UserMapper extends BaseMapper<User> {
}

在启动类中开启 mapper 扫描:

package com.sangui;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.sangui.mapper")
public class Mp01FirstApplication {
   public static void main(String[] args) {
       SpringApplication.run(Mp01FirstApplication.class, args);
  }
}

注意:@MapperScan 的包路径要与 UserMapper 所在包一致;使用 MyBatis-Plus starter 后,@MapperScan 和 Mapper 的自动注入通常可以正常工作。


基本 CRUD 示例(单表)

插入(insert)

JUnit 测试示例:

@Test
void insertTest() {
   User user = new User();
   user.setId(2);
   user.setAge(18);
   user.setName("李四");
   user.setEmail("lisi@qq.com");

   int count = userMapper.insert(user);
   System.out.println("数据库改变条数:" + count);
}

更新(update)——注意点

示例:

@Test
void updateTest() {
   User user = new User();
   user.setId(3);
   user.setAge(199);
   user.setName("王五9");
   user.setEmail("wangwu9@qq.com");

   int count = userMapper.updateById(user);
   System.out.println("数据库改变条数:" + count);
}

重要说明(关于空值处理) updateById 会根据实体构建更新语句。若实体中的某些字段为 null,可能会导致数据库列被更新为 NULL(覆盖原值)。如果你需要“选择性更新”(只更新非空字段),应:

  • 在构建实体时只设置需要更新的字段,或

  • 使用 UpdateWrapper/LambdaUpdateWrapper 明确指定要更新的列,或

  • 使用 MyBatis-Plus 提供的其它配置 / 插件来避免覆盖(例如自定义 MetaObjectHandler、手动判断);

总之,更新行为需在代码中显式控制,避免无意覆盖原有数据。

删除(delete)

@Test
void deleteTest(){
   int count = userMapper.deleteById(3);
   System.out.println("数据库改变条数:" + count);
}

查询(select)

@Test
void selectTest(){
   User user = userMapper.selectById(2);
   System.out.println(user);
}

自定义 SQL(XML)示例

UserMapper 中自定义方法签名:

List<User> selectAll(@Param("myname") String name, @Param("myage") Integer age);

对应的 mapper XML(放在 classpath:mapper/UserMapper.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.sangui.mapper.UserMapper">
   <select id="selectAll" resultType="com.sangui.domain.User">
      select id,name,email,age
      from u_user
      where name = #{myname} or age = #{myage}
      order by id
   </select>
</mapper>

测试代码:

@Test
void selectAllTest(){
   List<User> userList = userMapper.selectAll("张三", 30);
   System.out.println(userList);
}

条件构造器(QueryWrapper / LambdaQueryWrapper)

MyBatis-Plus 提供 QueryWrapperLambdaQueryWrapper 来构造动态 SQL 的 WHERE 部分,便于链式拼接条件。

等值查询、范围查询、组合查询、排序示例

  • 等值查询:

@Test
void selectEqTest(){
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   wrapper.eq("name","李四");
   List<User> userList = userMapper.selectList(wrapper);
   System.out.println(userList);
}

控制台 SQL 示例:

==>  Preparing: SELECT id,name,age,email FROM u_user WHERE (name = ?)
  • between(范围):

@Test
void selectBetweenTest(){
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   wrapper.between("age",18,19);
   List<User> userList = userMapper.selectList(wrapper);
   System.out.println(userList);
}

SQL:

Preparing: SELECT id,name,age,email FROM u_user WHERE (age BETWEEN ? AND ?)
  • 多条件(AND、IN):

@Test
void selectAndTest(){
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   wrapper.gt("age",17).eq("name","李四").in("email","lisi@qq.com","zhangsan@qq.com");
   List<User> userList = userMapper.selectList(wrapper);
   System.out.println(userList);
}

SQL:

==>  Preparing: SELECT id,name,age,email FROM u_user WHERE (age > ? AND name = ? AND email IN (?,?))
  • OR 示例:

@Test
void selectOrTest(){
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   wrapper.gt("age",17).or().eq("name","李四");
   List<User> userList = userMapper.selectList(wrapper);
   System.out.println(userList);
}

SQL:

==>  Preparing: SELECT id,name,age,email FROM u_user WHERE (age > ? OR name = ?)
  • 排序:

@Test
void selectOrderTest(){
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   wrapper.orderByDesc("age");
   List<User> userList = userMapper.selectList(wrapper);
   System.out.println(userList);
}

分页插件(Paging)配置与使用

  1. 引入分页相关依赖(示例):

<dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>mybatis-plus-boot-starter</artifactId>
   <version>3.5.12</version>
</dependency>
<!-- 如需 jsqlparser(部分高级 SQL 分析),按需添加 mybatis-plus-jsqlparser -->
<dependency>
   <groupId>com.baomidou</groupId>
   <artifactId>mybatis-plus-jsqlparser</artifactId>
   <version>3.5.12</version>
</dependency>
  1. 在配置类中注册拦截器(Bean):

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
   MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
   interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
   return interceptor;
}
  1. 使用示例:

@Test
void selectPageTest(){
   QueryWrapper<User> wrapper = new QueryWrapper<>();
   wrapper.gt("age",17);
   Page<User> userPage = userMapper.selectPage(Page.of(1, 10), wrapper);

   System.out.println(userPage);
   System.out.println("总页数 = " + userPage.getPages());
   System.out.println("每页的大小 = " + userPage.getSize());
   System.out.println("总记录条数 = " + userPage.getTotal());
   System.out.println("当前页号 = " + userPage.getCurrent());
   System.out.println("查询的记录 = " + userPage.getRecords());
}

日志与调试建议

application.yml 中配置 log-impl(上文已示例)可以把 SQL 输出到控制台,便于检查生成的 SQL。遇到 SQL 不符合预期时:

  • 打印完整 SQL(含参数)并在数据库中执行 EXPLAIN 分析性能;

  • 对复杂查询优先手写 SQL 并放在 XML 中,便于控制与调优;

  • 对更新操作谨慎处理 null 字段,避免误覆盖。


小结与注意事项

  • 使用 starter:在 Spring Boot 项目中应使用 MyBatis-Plus 的 starter,以确保与 Spring Boot 的自动配置正确集成。

  • 实体注解可选:当类名/字段名与数据库一致时,@TableName / @TableField / @TableId 并非强制;但显式标注有利于可读性和后续维护。

  • 更新慎重updateById 与类似 API 的空值覆盖问题需关注;若希望选择性更新,请明确只更新需要的字段或使用 Wrapper。

  • 条件构造器灵活QueryWrapperLambdaQueryWrapper 支持链式拼接,适合动态查询;但复杂查询建议回退到 XML 手写 SQL 以保证可控性与性能。

  • 分页与拦截器:MyBatis-Plus 的分页插件使用简单,建议按需注册并结合 Page 对象获取分页信息。

  • 学习建议:将常见 CRUD、Wrapper、分页与自定义 SQL 都写成测试用例,有助于快速回归验证逻辑与 SQL 输出。

  • 微信
  • 赶快加我聊天吧
  • QQ
  • 赶快加我聊天吧
  • weinxin
三桂

发表评论 取消回复 您未登录,登录后才能评论,前往登录