MyBatis-Plus(简称 MP)是 MyBatis 的增强工具,在 MyBatis 基础上只做增强不做改变,旨在简化开发、提高效率。本文从实战使用和最佳实践两方面,结合实际开发场景,带你全面掌握 MP 的核心用法。
以 Spring Boot 项目为例,核心依赖如下(需配合 MyBatis、数据库驱动):
<!-- MyBatis-Plus 核心依赖 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version> <!-- 推荐使用最新稳定版 -->
</dependency>
<!-- 数据库驱动(以 MySQL 8.0 为例) -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 可选:代码生成器(高效生成实体、Mapper 等) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.5</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId> <!-- 模板引擎,也可选用 Velocity -->
</dependency>核心配置:数据源、MyBatis-Plus 基础配置
spring:
datasource:
url: jdbc:mysql://localhost:3306/mp_demo?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
# Mapper.xml 文件路径(如果使用 XML 编写复杂 SQL)
mapper-locations: classpath:mapper/*.xml
# 实体类别名包路径(简化 XML 中类名引用)
type-aliases-package: com.example.mpdemo.entity
configuration:
# 开启驼峰命名自动转换(数据库字段下划线 -> Java 驼峰)
map-underscore-to-camel-case: true
# 打印 SQL(开发环境开启,生产环境关闭)
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
# 全局逻辑删除字段名(统一逻辑删除字段,如 is_deleted)
logic-delete-field: isDeleted
# 逻辑删除:1=已删除,0=未删除
logic-delete-value: 1
logic-not-delete-value: 0添加 @MapperScan 扫描 Mapper 接口所在包:
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.mpdemo.mapper") // Mapper 接口包路径
public class MpDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MpDemoApplication.class, args);
}
}MP 通过注解映射数据库表/字段,核心注解:
@TableName:映射数据库表名(表名与类名一致可省略)@TableId:主键字段(必选),指定主键策略@TableField:普通字段(字段名与属性名一致可省略)@TableLogic:逻辑删除字段(配合全局配置或单独指定)示例:
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;
@Data // Lombok 简化 getter/setter(可选)
@TableName("t_user") // 数据库表名:t_user
public class User {
// 主键:自增策略(MySQL 自增字段)
@TableId(type = IdType.AUTO)
private Long id;
// 普通字段:数据库字段名 user_name(驼峰自动转换)
private String userName;
private Integer age;
// 逻辑删除字段(配合全局配置,也可单独指定 value)
@TableLogic
private Integer isDeleted;
// 自动填充:创建时间(插入时填充)
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
// 自动填充:更新时间(插入/更新时填充)
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}如果实体类有 createTime/updateTime 等需要自动填充的字段,需实现 MetaObjectHandler:
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
// 插入时填充
@Override
public void insertFill(MetaObject metaObject) {
strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
// 更新时填充
@Override
public void updateFill(MetaObject metaObject) {
strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}MP 提供 BaseMapper 接口,包含 CRUD 基础方法,Mapper 接口只需继承 BaseMapper<实体类> 即可直接使用,无需编写 XML。
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mpdemo.entity.User;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<User> {
// 无需编写任何方法,直接使用 BaseMapper 中的 CRUD 方法
}方法 | 功能描述 | 示例 |
|---|---|---|
| 新增一条记录 |
|
| 根据主键删除 |
|
| 根据主键更新 |
|
| 根据主键查询 |
|
| 条件查询列表 | 见下文条件构造器示例 |
| 分页查询 | 见下文分页示例 |
MP 提供强大的条件构造器,支持动态 SQL 拼接,无需手动写 WHERE 条件。推荐使用 LambdaQueryWrapper(类型安全,避免字段名写错)。
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.mapper.UserMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class UserService {
@Resource
private UserMapper userMapper;
// 条件查询:查询年龄 > 18 且用户名包含 "张" 的用户
public List<User> queryUser() {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>()
.gt(User::getAge, 18) // age > 18
.like(User::getUserName, "张"); // user_name LIKE '%张%'
return userMapper.selectList(queryWrapper);
}
// 动态条件:根据传入参数拼接条件(如用户名可为空)
public List<User> queryUserByCondition(String userName, Integer age) {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>()
.like(userName != null, User::getUserName, userName) // 条件成立才拼接
.ge(age != null, User::getAge, age); // age >= 传入值
return userMapper.selectList(queryWrapper);
}
}方法 | 功能描述 | 示例 |
|---|---|---|
| 等于(=) |
|
| 不等于(!=) |
|
| 大于(>) |
|
| 大于等于(>=) |
|
| 小于(<) |
|
| 小于等于(<=) |
|
| 模糊查询(LIKE) |
|
| 左模糊(LIKE '%值') |
|
| IN 查询 |
|
| 字段为 NULL |
|
| 升序排序 |
|
| 降序排序 |
|
MP 内置分页插件,无需额外配置(3.5+ 版本自动注入),直接使用 Page 类即可实现分页。
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.mpdemo.entity.User;
import com.example.mpdemo.mapper.UserMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserService {
@Resource
private UserMapper userMapper;
// 分页查询:第 1 页,每页 10 条,条件:年龄 > 18
public IPage<User> queryUserByPage(Integer pageNum, Integer pageSize) {
// 1. 构建分页对象(pageNum:页码,pageSize:每页条数)
Page<User> page = new Page<>(pageNum, pageSize);
// 2. 构建查询条件
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>()
.gt(User::getAge, 18);
// 3. 分页查询(返回 IPage,包含总条数、当前页数据等)
return userMapper.selectPage(page, queryWrapper);
}
}方法 | 功能描述 |
|---|---|
| 总记录数 |
| 总页数 |
| 当前页码 |
| 每页条数 |
| 当前页数据列表 |
| 是否有下一页 |
| 是否有上一页 |
对于复杂 SQL(如多表联查、分组统计),MP 支持保留 MyBatis 原生写法,可通过 XML 或注解实现。
import org.apache.ibatis.annotations.Select;
import java.util.List;
public interface UserMapper extends BaseMapper<User> {
// 注解方式编写简单 SQL
@Select("SELECT * FROM t_user WHERE age = #{age} AND is_deleted = 0")
List<User> selectByAge(@Param("age") Integer age);
}MP 代码生成器可自动生成 实体类、Mapper 接口、Service、Controller,减少重复编码。
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import java.util.Collections;
public class CodeGenerator {
public static void main(String[] args) {
// 数据库连接配置
String url = "jdbc:mysql://localhost:3306/mp_demo?useSSL=false&serverTimezone=Asia/Shanghai";
String username = "root";
String password = "123456";
// 代码生成配置
FastAutoGenerator.create(url, username, password)
// 全局配置
.globalConfig(builder -> {
builder.author("your-name") // 作者名
.outputDir(System.getProperty("user.dir") + "/src/main/java") // 输出目录
.disableOpenDir() // 生成后不打开文件夹
.commentDate("yyyy-MM-dd"); // 注释日期格式
})
// 包配置(生成的类所在包)
.packageConfig(builder -> {
builder.parent("com.example.mpdemo") // 父包名
.entity("entity") // 实体类包名
.mapper("mapper") // Mapper 接口包名
.service("service") // Service 包名
.controller("controller") // Controller 包名
.xml("mapper") // Mapper XML 包名(resources/mapper)
.pathInfo(Collections.singletonMap(OutputFile.xml,
System.getProperty("user.dir") + "/src/main/resources/mapper"));
})
// 策略配置
.strategyConfig(builder -> {
builder.addInclude("t_user", "t_order") // 要生成的数据库表名(多个表用逗号分隔)
.addTablePrefix("t_") // 表前缀(生成实体类时去掉前缀,如 t_user -> User)
// 实体类策略
.entityBuilder()
.enableLombok() // 启用 Lombok
.enableTableFieldAnnotation() // 生成字段注解(@TableField)
.logicDeleteFieldName("is_deleted") // 逻辑删除字段
.addTableFills(
// 自动填充配置
com.baomidou.mybatisplus.generator.fill.ColumnFill.INSERT, "create_time"
)
.addTableFills(
com.baomidou.mybatisplus.generator.fill.ColumnFill.INSERT_UPDATE, "update_time"
)
// Mapper 策略
.mapperBuilder()
.enableBaseResultMap() // 启用 BaseResultMap(XML 中生成结果映射)
.enableBaseColumnList() // 启用 BaseColumnList(XML 中生成字段列表)
// Service 策略
.serviceBuilder()
.formatServiceFileName("%sService") // Service 接口名格式(如 UserService)
.formatServiceImplFileName("%sServiceImpl") // Service 实现类名格式
// Controller 策略
.controllerBuilder()
.enableRestStyle(); // 启用 REST 风格(@RestController)
})
// 模板引擎(Freemarker)
.templateEngine(new FreemarkerTemplateEngine())
// 执行生成
.execute();
}
}t_ 前缀(如 t_user),字段名用下划线命名(如 user_name),实体类用驼峰命名(userName),配合 map-underscore-to-camel-case: true 自动转换。IdType.AUTO(需数据库字段设置自增)。IdType.ASSIGN_ID(MP 内置雪花算法,生成 19 位 Long 型 ID,无需数据库配置)。is_deleted 字段),避免物理删除数据,通过全局配置简化注解。user_name),减少字段名修改导致的 Bug。like(condition, column, value)),避免拼接无效 SQL。and/or 嵌套,提高可读性:// 嵌套条件:(age > 18 AND user_name LIKE '%张%') OR (age < 10 AND user_name LIKE '%李%')
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>()
.and(w -> w.gt(User::getAge, 18).like(User::getUserName, "张"))
.or(w -> w.lt(User::getAge, 10).like(User::getUserName, "李"));select(字段...) 指定需要的字段,减少数据传输:LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<User>()
.select(User::getId, User::getUserName) // 只查询 id 和 user_name
.gt(User::getAge, 18);WHERE 条件和 ORDER BY 字段必须建索引,避免全表扫描(如 age 和 create_time 字段建索引)。saveBatch/updateBatchById:MP 提供批量插入/更新方法,内部优化了 JDBC 批处理,比循环单条操作效率高:// 批量插入(推荐批量大小 1000 以内)
List<User> userList = new ArrayList<>();
// ... 添加数据
userMapper.saveBatch(userList, 500); // 每 500 条提交一次selectList 无限制查询:如果数据量较大,必须使用分页查询,防止内存溢出。log-impl 配置只在开发环境开启,生产环境关闭,避免日志泄露敏感信息。MybatisPlusException 及其子类,可针对性捕获数据库操作异常:try {
userMapper.insert(user);
} catch (MybatisPlusException e) {
log.error("新增用户失败:{}", e.getMessage(), e);
throw new BusinessException("用户创建失败"); // 业务异常
}BaseMapper:不要直接在 Mapper 接口写大量方法,复杂 SQL 抽离到 XML 或单独的 Mapper 方法。@Param 注解:多参数查询时,用 @Param 指定参数名,避免 XML 中参数绑定错误。@Version 注解(数据库字段需为 int 类型):@Version
private Integer version; // 乐观锁版本号字段@TableField 注解。@TableId 类型为 IdType.AUTO。@TableLogic 注解,SQL 是否自动拼接 is_deleted = 0。Page 的页码和每页条数是否正确,查询条件是否过滤了所有数据。@Data 可自动生成),MP 版本是否为 3.5+。MyBatis-Plus 核心价值是简化开发、提高效率,通过 BaseMapper、条件构造器、分页插件等特性,减少重复编码。实战中需遵循数据库设计规范、合理使用 Lambda 条件构造器、封装业务逻辑,同时注意性能优化和代码维护性。掌握以上内容,可覆盖 90% 以上的业务场景,大幅提升开发效率。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。