MyBatis-Plus 全方位使用指南:从基础 CRUD 到复杂查询
在 Java 后端开发中,数据库操作是核心环节之一。MyBatis 作为常用的 ORM 框架,虽灵活但需编写大量 XML 配置和 SQL 语句。而 MyBatis-Plus(简称 MP)作为 MyBatis 的增强工具,在保留 MyBatis 特性的基础上,大幅简化开发流程,提升效率。本文将从 MyBatis-Plus 介绍、快速上手、复杂操作等方面,带你全面掌握其使用方法。
一、MyBatis-Plus 简介
MyBatis-Plus 是一款基于 MyBatis 的增强工具,秉持 “只做增强,不做改变” 的理念,旨在简化开发、提高效率,已连续 5 年获得开源中国年度最佳开源项目殊荣,在 Github 上累计拥有 16K Star。
1.1 核心特性
- 润物无声:引入后不会对现有工程产生影响,集成过程顺滑自然,无需修改原有 MyBatis 相关代码。
- 效率至上:仅需简单配置,就能快速实现单表 CRUD 操作,省去大量重复编码工作,节省开发时间。
- 丰富功能:提供代码生成、自动分页、逻辑删除、自动填充、拦截器等实用功能,满足多样化开发需求。
- 广泛兼容:支持 PostgreSQL、MySQL、MariaDB、Oracle、SQL Server 等多种数据库,只要能通过 MyBatis 进行增删改查且支持标准 SQL 的数据库,基本都能适配。
1.2 官网地址
MyBatis-Plus 官方网站:MyBatis-Plus 🚀 为简化开发而生,官网提供了详细的文档和示例,是学习和使用 MyBatis-Plus 的重要参考。
二、MyBatis-Plus 快速上手
使用 MyBatis-Plus 操作数据库,主要分为准备工作、编码、测试三个步骤,下面将逐步详细介绍。
2.1 准备工作
2.1.1 数据准备
首先创建数据库和用户表,并插入测试数据。这里我们继续使用 MyBatis 学习阶段的数据库表结构,SQL 语句如下:
-- 创建数据库
DROP DATABASE IF EXISTS mybatis_test;
CREATE DATABASE mybatis_test DEFAULT CHARACTER SET utf8mb4;-- 使用数据库
USE mybatis_test;-- 创建用户表
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 mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
2.1.2 项目准备
- 创建 Spring Boot 工程:可通过 Spring Initializr 快速创建,选择合适的 Spring Boot 版本、Group、Artifact 等信息。
- 引入依赖:根据 Spring Boot 版本不同,引入对应的 MyBatis-Plus 和 MySQL 依赖。
- Spring Boot 2 版本依赖:
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.7</version> </dependency> <dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope> </dependency>
2. Spring Boot 3 版本依赖:
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-spring-boot3-starter</artifactId><version>3.5.5</version> </dependency> <dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope> </dependency>
- 配置数据库连接信息:可选择 application.yml 或 application.properties 文件进行配置。
- application.yml 配置:
# 数据库连接配置 spring:datasource:url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driver
2. application.properties 配置:
# 驱动类名称 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # 数据库连接的url spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false # 连接数据库的用户名 spring.datasource.username=root # 连接数据库的密码 spring.datasource.password=root
2.2 编码
2.2.1 创建实体类
创建与数据库表user_info
对应的实体类UserInfo
,使用 Lombok 的@Data
注解简化 getter、setter 等方法的编写,实体类属性名与表中字段名一一对应:
import lombok.Data;
import java.util.Date;@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;
}
2.2.2 编写 Mapper 接口
MyBatis-Plus 提供了基础的BaseMapper
接口,该接口已实现单表的 CRUD 操作。自定义的 Mapper 接口只需继承BaseMapper
,并指定泛型为对应的实体类,即可直接使用 CRUD 方法,无需自己编写实现。同时,可在接口上添加@Mapper
注解,或在启动类上添加@MapperScan
注解扫描 Mapper 文件夹,两种方式二选一。
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mybatisplusdemo.entity.UserInfo;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {
}
2.3 CRUD 单元测试
在 Spring Boot 工程的 test 目录下,编写单元测试类,注入UserInfoMapper
实例,对基本的 CRUD 功能进行测试。
import com.example.mybatisplusdemo.entity.UserInfo;
import com.example.mybatisplusdemo.mapper.UserInfoMapper;
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 MybatisPlusDemoApplicationTests {@Autowiredprivate UserInfoMapper userInfoMapper;// 新增测试@Testvoid testInsert() {UserInfo user = new UserInfo();user.setUsername("bite");user.setPassword("123456");user.setAge(11);user.setGender(0);user.setPhone("18610001234");userInfoMapper.insert(user);}// 根据ID查询测试@Testvoid testSelectById() {UserInfo user = userInfoMapper.selectById(1);System.out.println("user: " + user);}// 批量查询测试@Testvoid testSelectByIds() {List<UserInfo> users = userInfoMapper.selectBatchIds(List.of(1, 2, 3, 4));users.forEach(System.out::println);}// 根据ID更新测试@Testvoid testUpdateById() {UserInfo user = new UserInfo();user.setId(1);user.setPassword("4444444");userInfoMapper.updateById(user);}// 根据ID删除测试@Testvoid testDelete() {userInfoMapper.deleteById(5);}
}
运行测试方法后,从控制台输出结果可以看到,数据的 CRUD 操作全部执行成功,数据库中的数据也会相应地发生变化。
三、MyBatis-Plus 复杂操作
在实际开发中,除了基础的 CRUD 操作,还会涉及到一些复杂的数据库操作,MyBatis-Plus 也提供了相应的解决方案,如常见注解、条件构造器、自定义 SQL 等。
3.1 常见注解
MyBatis-Plus 默认会根据实体类推断数据库表的信息,默认规则如下:
- 表名:实体类的驼峰表示法转换为蛇形表示法(下划线分割),例如
UserInfo
对应表名user_info
。 - 字段:实体类的属性名转换为蛇形表示法作为字段名,例如
deleteFlag
对应字段名delete_flag
。 - 主键:默认为
id
。
当实体类和数据库表不遵循上述默认规则时,可通过以下注解进行标识。
3.1.1 @TableName
该注解用于指定实体类对应的数据库表名。例如,若将实体类名UserInfo
改为Userinfo
,默认情况下 MyBatis-Plus 会查找表名userinfo
,而实际数据库表名为user_info
,此时就需要使用@TableName
注解指定表名:
import lombok.Data;
import com.baomidou.mybatisplus.annotation.TableName;
import java.util.Date;@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;
}
3.1.2 @TableField
该注解用于指定实体类属性对应的数据库表字段名。例如,若将实体类属性deleteFlag
改为deleteflag
,默认情况下 MyBatis-Plus 会查找字段名deleteflag
,而实际数据库字段名为delete_flag
,此时可使用@TableField
注解指定字段名:
import lombok.Data;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableField;
import java.util.Date;@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;
}
3.1.3 @TableId
该注解用于指定实体类属性对应的数据库表主键。例如,若将实体类属性id
改为userId
,默认情况下 MyBatis-Plus 无法识别主键,此时可使用@TableId
注解指定主键:
import lombok.Data;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import java.util.Date;@Data
@TableName("user_info")
public class Userinfo {@TableId("id")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
注解即可。
3.2 打印日志
为了方便调试,查看 MyBatis-Plus 执行的 SQL 语句、参数和执行结果,可在配置文件中配置日志打印。以 application.yml 为例:
mybatis-plus:configuration:# 配置打印 MyBatis 日志log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
配置完成后,运行测试方法,控制台会输出详细的 SQL 执行日志。
3.3 条件构造器
MyBatis-Plus 提供了一套强大的条件构造器(Wrapper),用于构建复杂的数据库查询条件,支持链式调用,无需编写繁琐的 SQL 语句,同时能减少 SQL 注入的风险。主要的 Wrapper 类及其功能如下:
条件构造器类 | 功能描述 |
---|---|
AbstractWrapper | 抽象基类,提供所有 Wrapper 类共有的方法和属性,是其他 Wrapper 类的父类 |
QueryWrapper | 用于构造查询条件,在 AbstractWrapper 基础上拓展 select 方法,可指定查询字段 |
UpdateWrapper | 用于构造更新条件,可在更新数据时指定条件,也可直接设置更新字段 |
LambdaQueryWrapper | 基于 Lambda 表达式的查询条件构造器,通过 Lambda 表达式引用实体类属性,避免硬编码字段名 |
LambdaUpdateWrapper | 基于 Lambda 表达式的更新条件构造器,支持 Lambda 表达式指定更新字段和条件,避免硬编码字段名 |
3.3.1 QueryWrapper
QueryWrapper 不仅可用于查询操作,还可用于修改、删除操作,用于构建相应的条件。
- 查询操作:例如查询
age = 18
且username
包含 “min” 的用户信息,并只查询id
、username
、password
、age
字段:
@Test
void testQueryWrapper() {QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>().select("id", "username", "password", "age").eq("age", 18).like("username", "min");List<UserInfo> userInfos = userInfoMapper.selectList(userInfoQueryWrapper);userInfos.forEach(System.out::println);
}
需要注意的是,默认情况下 MyBatis-Plus 会根据@TableField
生成别名,当指定 QueryWrapper 的 select 属性后,查询结果可能因字段名不匹配无法正确映射。解决办法有:自定义 SQL、保持实体类名和字段名一致、不指定 select 字段、使用 LambdaQueryWrapper。
2. 更新操作:例如将age < 20
的用户delete_flag
设为 1:
@Test
void testUpdateByQueryWrapper() {QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>().lt("age", 20);UserInfo userInfo = new UserInfo();userInfo.setDeleteFlag(1);userInfoMapper.update(userInfo, userInfoQueryWrapper);
}
其中,lt
是 “less than” 的缩写,表示 “小于”,类似的还有le
(小于等于)、ge
(大于等于)、gt
(大于)、eq
(等于)、ne
(不等于)等方法。
3. 删除操作:例如删除age = 18
的用户信息:
@Test
void testDeleteByQueryWrapper() {QueryWrapper<UserInfo> userInfoQueryWrapper = new QueryWrapper<UserInfo>().eq("age", 18);userInfoMapper.delete(userInfoQueryWrapper);
}
3.3.2 UpdateWrapper
使用 UpdateWrapper 可在不创建实体对象的情况下,直接设置更新字段和条件,更加灵活。
- 基础更新:例如将
id
在 1、2、3 范围内的用户delete_flag
设为 0,age
设为 5:
@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(null, updateWrapper);
}
2. 基于 SQL 更新:例如将id
在 1、2、3 范围内的用户age
增加 10:
@Test
void testUpdateBySQLUpdateWrapper() {UpdateWrapper<UserInfo> updateWrapper = new UpdateWrapper<UserInfo>().setSql("age = age + 10").in("id", List.of(1, 2, 3));userInfoMapper.update(null, updateWrapper);
}
3.3.3 LambdaQueryWrapper
QueryWrapper 和 UpdateWrapper 存在硬编码字段名的问题,若字段名发生变更,可能因测试不到位引发错误。LambdaQueryWrapper 基于 Lambda 表达式,通过引用实体类属性构建查询条件,避免硬编码字段名,提高代码可读性和可维护性。例如查询userId = 1
的用户username
、password
、age
信息:
@Test
void testLambdaQueryWrapper() {LambdaQueryWrapper<UserInfo> lambdaQueryWrapper = new LambdaQueryWrapper<UserInfo>().select(UserInfo::getUsername, UserInfo::getPassword, UserInfo::getAge).eq(UserInfo::getUserId, 1);List<UserInfo> userInfos = userInfoMapper.selectList(lambdaQueryWrapper);userInfos.forEach(System.out::println);
}
3.3.4 LambdaUpdateWrapper
LambdaUpdateWrapper 用法与 LambdaQueryWrapper 类似,基于 Lambda 表达式构建更新条件和更新字段,避免硬编码字段名。例如将userId
在 1、2、3 范围内的用户delete_flag
设为 0,age
设为 5:
@Test
void testLambdaUpdateByUpdateWrapper() {LambdaUpdateWrapper<UserInfo> lambdaUpdateWrapper = new LambdaUpdateWrapper<UserInfo>().set(UserInfo::getDeleteFlag, 0).set(UserInfo::getAge, 5).in(UserInfo::getUserId, List.of(1, 2, 3));userInfoMapper.update(null, lambdaUpdateWrapper);
}
3.4 自定义 SQL
当 MyBatis-Plus 提供的操作无法满足实际开发需求时,可使用自定义 SQL 功能,结合 Wrapper 构造查询条件,编写符合业务需求的 SQL 语句。需要注意的是,使用该功能要求 MyBatis-Plus 版本不低于 3.0.7。
3.4.1 注解方式自定义 SQL
例如查询username = "admin"
的用户id
、username
、password
、age
信息,通过注解方式实现:
- 在 Mapper 接口中定义方法,使用
@Select
注解编写 SQL 语句,通过${ew.customSqlSegment}
引用 Wrapper 生成的 SQL 片段,参数需使用@Param(Constants.WRAPPER)
指定为 Wrapper 对象:
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.example.mybatisplusdemo.entity.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Param;
import java.util.List;@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);
}
2. 编写测试方法
@Test
void testQueryUserByCustom() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>().eq("username", "admin");List<UserInfo> userInfos = userInfoMapper.queryUserByCustom(queryWrapper);userInfos.forEach(System.out::println);
}
3.4.2 XML 方式自定义 SQL
MyBatis-Plus 兼容 MyBatis 的 XML 配置方式,也可通过 XML 编写自定义 SQL。例如实现上述相同的查询功能:
- 在配置文件中指定 Mapper XML 文件的路径,以 application.yml 为例:
mybatis-plus:mapper-locations: "classpath*:/mapper/**.xml" # Mapper XML文件路径
2. 在 Mapper 接口中定义方法
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.example.mybatisplusdemo.entity.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {List<UserInfo> queryUserByCustom2(@Param(Constants.WRAPPER) Wrapper<UserInfo> wrapper);
}
3. 在 resources/mapper 目录下创建对应的 XML 文件(如 UserInfoMapper.xml),编写 SQL 语句:
<?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.example.mybatisplusdemo.mapper.UserInfoMapper"><select id="queryUserByCustom2" resultType="com.example.mybatisplusdemo.entity.UserInfo">select id, username, password, age FROM user_info ${ew.customSqlSegment}</select>
</mapper>
4. 编写测试方法:
@Test
void testQueryUserByCustom2() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>().eq("username", "admin");List<UserInfo> userInfos = userInfoMapper.queryUserByCustom2(queryWrapper);userInfos.forEach(System.out::println);
}
3.4.3 自定义更新 SQL
除了查询操作,自定义 SQL 也可用于更新操作。例如将id
在 1、2、3 范围内的用户age
增加指定数值:
- 在 Mapper 接口中定义方法:
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mybatisplusdemo.entity.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;@Mapper
public interface UserInfoMapper extends BaseMapper<UserInfo> {@Update("UPDATE user_info SET age = age + #{addAge} ${ew.customSqlSegment}")void updateUserByCustom(@Param("addAge") int addAge, @Param("ew") Wrapper<UserInfo> wrapper);
}
2. 编写测试方法:
@Test
void updateUserByCustom() {QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<UserInfo>().in("id", List.of(1, 2, 3));userInfoMapper.updateUserByCustom(10, queryWrapper);
}
四、总结
MyBatis-Plus 作为 MyBatis 的增强工具,极大地简化了数据库操作的开发流程。通过本文的介绍,我们了解到:
- MyBatis-Plus 在 MyBatis 基础上只做增强不做改变,能以更少的代码实现数据库表的 CRUD 操作,显著提升开发效率。
- 快速上手 MyBatis-Plus 需完成数据准备、项目准备、编码、测试等步骤,其中继承
BaseMapper
接口是实现基础 CRUD 的关键。 - 面对复杂操作,MyBatis-Plus 提供了常见注解(
@TableName
、@TableField
、@TableId
)解决实体类与数据库表的映射问题,通过条件构造器(QueryWrapper、UpdateWrapper、LambdaQueryWrapper、LambdaUpdateWrapper)构建复杂查询条件,还支持自定义 SQL 满足特殊业务需求。
在实际开发中,合理运用 MyBatis-Plus 的这些功能,能有效减少重复编码,降低开发难度,让开发者更专注于业务逻辑的实现。如果你还未使用过 MyBatis-Plus,不妨在项目中尝试一下,相信它会给你带来意想不到的开发体验!