当前位置: 首页 > news >正文

SpringBoot之整合MyBatisPlus

SpringBoot之整合MyBatisPlus—简化CRUD操作的实战指南

    • 一、MyBatisPlus的优势
    • 二、环境准备
    • 三、SpringBoot整合MyBatisPlus步骤
      • 3.1 创建项目并添加依赖
      • 3.2 配置数据库连接
      • 3.3 创建数据库表
      • 3.4 编写实体类(Entity)
      • 3.5 实现自动填充(元对象处理器)
      • 3.6 创建Mapper接口
      • 3.7 注册Mapper接口
      • 3.8 编写Service层(可选)
        • 3.8.1 定义Service接口
        • 3.8.2 实现Service接口
    • 四、MyBatisPlus核心功能实战
      • 4.1 基础CRUD操作(基于Service)
      • 4.2 条件查询(QueryWrapper/LambdaQueryWrapper)
      • 4.3 分页查询
        • 4.3.1 配置分页插件
        • 4.3.2 实现分页查询
      • 4.4 自定义SQL(XML方式)
        • 4.4.1 在Mapper接口中定义方法
        • 4.4.2 创建XML映射文件
        • 4.4.3 在Service中调用
    • 五、MyBatisPlus高级特性
      • 5.1 代码生成器(AutoGenerator)
        • 5.1.1 添加代码生成器依赖
        • 5.1.2 编写生成器配置类
      • 5.2 乐观锁插件
        • 5.2.1 配置乐观锁插件
        • 5.2.2 在实体类添加版本字段
        • 5.2.3 使用乐观锁
    • 六、常见问题与避坑指南
      • 6.1 依赖冲突问题
      • 6.2 逻辑删除失效
      • 6.3 分页查询返回总数为0
      • 6.4 LambdaQueryWrapper字段引用错误
      • 总结

在Java开发中,MyBatis作为主流ORM框架被广泛使用,但原生写XML映射文件或注解SQL仍需大量重复工作,MyBatisPlus(简称MP)在MyBatis基础上增强了CRUD操作,通过内置接口实现无SQL开发,大幅提升开发效率。

一、MyBatisPlus的优势

MyBatisPlus是一个MyBatis的增强工具,在保留MyBatis原有功能的基础上,提供了以下核心优势:

  • 无SQL实现CRUD:内置BaseMapper接口,提供单表增删改查操作,无需编写SQL;
  • 条件构造器:通过QueryWrapper/LambdaQueryWrapper灵活组装查询条件,替代XML中的动态SQL;
  • 代码生成器:自动生成实体类、Mapper、Service等代码,减少重复劳动;
  • 分页插件:一键集成分页功能,无需手动编写分页SQL;
  • 全局主键策略:支持雪花算法、自增等多种主键生成策略,无需手动设置ID;
  • 逻辑删除:通过注解实现逻辑删除(更新is_deleted字段),无需修改SQL。

MyBatisPlus与MyBatis的关系类似:MyBatisPlus = MyBatis + 增强功能,完全兼容MyBatis的用法,可平滑过渡。

二、环境准备

  • JDK:1.8及以上;
  • 开发工具:IntelliJ IDEA;
  • 构建工具:Maven 3.6+;
  • 数据库:MySQL 8.0;
  • SpringBoot版本:2.7.x;
  • MyBatisPlus版本:3.5.x。

三、SpringBoot整合MyBatisPlus步骤

3.1 创建项目并添加依赖

通过Spring Initializr创建项目,或手动添加以下依赖:

<!-- pom.xml核心依赖 -->
<dependencies><!-- SpringBoot Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MyBatisPlus起步依赖(包含MyBatis) --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.3.1</version></dependency><!-- MySQL驱动 --><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><!-- Lombok(简化实体类) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>

注意:引入mybatis-plus-boot-starter后,无需再单独引入MyBatis的依赖,避免版本冲突。

3.2 配置数据库连接

application.yml中配置数据源和MyBatisPlus参数:

# application.yml
server:port: 8080spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mp_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghaiusername: rootpassword: root # 替换为实际密码# MyBatisPlus配置
mybatis-plus:# 实体类包路径(别名配置)type-aliases-package: com.example.mp.entity# 映射文件路径(若需要XML方式写SQL)mapper-locations: classpath:mapper/*.xmlconfiguration:# 日志打印(开发环境用)log-impl: org.apache.ibatis.logging.stdout.StdOutImpl# 驼峰命名转换(数据库字段user_name → 实体类userName)map-underscore-to-camel-case: trueglobal-config:db-config:# 全局主键策略:ASSIGN_ID(雪花算法,分布式ID)id-type: ASSIGN_ID# 逻辑删除字段名(默认为is_deleted)logic-delete-field: isDeleted# 逻辑删除值(1:已删除)logic-delete-value: 1# 未删除值(0:未删除)logic-not-delete-value: 0

3.3 创建数据库表

user表为例,创建测试数据:

-- 创建数据库
CREATE DATABASE IF NOT EXISTS mp_demo CHARACTER SET utf8mb4;
USE mp_demo;-- 创建用户表
CREATE TABLE user (id BIGINT PRIMARY KEY COMMENT '主键ID',username VARCHAR(50) NOT NULL COMMENT '用户名',age INT COMMENT '年龄',email VARCHAR(100) COMMENT '邮箱',create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',is_deleted TINYINT DEFAULT 0 COMMENT '逻辑删除(0:未删,1:已删)'
) COMMENT '用户表';-- 插入测试数据
INSERT INTO user (username, age, email) VALUES 
('张三', 20, 'zhangsan@example.com'),
('李四', 22, 'lisi@example.com'),
('王五', 25, 'wangwu@example.com');

3.4 编写实体类(Entity)

使用Lombok和MyBatisPlus注解定义实体类:

package com.example.mp.entity;import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;@Data
@TableName("user") // 指定数据库表名(若类名与表名一致可省略)
public class User {// 主键(全局策略:雪花算法)@TableId(type = IdType.ASSIGN_ID)private Long id;private String username;private Integer age;private String email;// 自动填充:创建时间@TableField(fill = FieldFill.INSERT)private LocalDateTime createTime;// 自动填充:更新时间@TableField(fill = FieldFill.INSERT_UPDATE)private LocalDateTime updateTime;// 逻辑删除字段@TableLogicprivate Integer isDeleted;
}

核心注解说明

  • @TableName:指定实体类对应的数据库表名;
  • @TableId:标记主键字段,type = IdType.ASSIGN_ID表示使用雪花算法生成ID;
  • @TableField:标记普通字段,fill属性用于配置自动填充策略;
  • @TableLogic:标记逻辑删除字段。

3.5 实现自动填充(元对象处理器)

createTimeupdateTime字段实现自动填充(创建时自动设置时间,更新时自动更新时间):

package com.example.mp.handler;import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;@Component // 注册为Spring组件
public class MyMetaObjectHandler implements MetaObjectHandler {// 插入时自动填充@Overridepublic void insertFill(MetaObject metaObject) {// 填充createTime和updateTime为当前时间this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}// 更新时自动填充@Overridepublic void updateFill(MetaObject metaObject) {// 填充updateTime为当前时间this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());}
}

3.6 创建Mapper接口

继承MyBatisPlus的BaseMapper接口,无需编写方法即可获得CRUD功能:

package com.example.mp.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mp.entity.User;// 继承BaseMapper<User>,泛型为实体类
public interface UserMapper extends BaseMapper<User> {// 无需编写方法,BaseMapper已提供CRUD操作
}

3.7 注册Mapper接口

在SpringBoot启动类上添加@MapperScan注解,扫描Mapper接口所在包:

package com.example.mp;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
@MapperScan("com.example.mp.mapper") // 扫描Mapper接口
public class MybatisPlusDemoApplication {public static void main(String[] args) {SpringApplication.run(MybatisPlusDemoApplication.class, args);}
}

3.8 编写Service层(可选)

MyBatisPlus提供IServiceServiceImpl简化Service层开发,比传统Service更高效:

3.8.1 定义Service接口
package com.example.mp.service;import com.baomidou.mybatisplus.extension.service.IService;
import com.example.mp.entity.User;// 继承IService<User>
public interface UserService extends IService<User> {// 可添加自定义业务方法
}
3.8.2 实现Service接口
package com.example.mp.service.impl;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.mp.entity.User;
import com.example.mp.mapper.UserMapper;
import com.example.mp.service.UserService;
import org.springframework.stereotype.Service;@Service
// 继承ServiceImpl<UserMapper, User>,实现UserService
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {// 无需编写基础CRUD方法,已由ServiceImpl实现
}

四、MyBatisPlus核心功能实战

4.1 基础CRUD操作(基于Service)

package com.example.mp.controller;import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.mp.entity.User;
import com.example.mp.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;// 1. 新增用户@PostMappingpublic String addUser(@RequestBody User user) {boolean save = userService.save(user);return save ? "新增成功,ID:" + user.getId() : "新增失败";}// 2. 根据ID查询@GetMapping("/{id}")public User getUserById(@PathVariable Long id) {return userService.getById(id);}// 3. 查询所有用户@GetMappingpublic List<User> getAllUsers() {return userService.list();}// 4. 更新用户@PutMappingpublic String updateUser(@RequestBody User user) {boolean update = userService.updateById(user);return update ? "更新成功" : "更新失败";}// 5. 删除用户(逻辑删除)@DeleteMapping("/{id}")public String deleteUser(@PathVariable Long id) {boolean remove = userService.removeById(id);return remove ? "删除成功" : "删除失败";}
}

测试结果:调用DELETE /users/1后,数据库中is_deleted字段会被更新为1(而非物理删除),查询时会自动过滤已删除数据。

4.2 条件查询(QueryWrapper/LambdaQueryWrapper)

使用条件构造器实现复杂查询,替代XML中的动态SQL:

@GetMapping("/query")
public List<User> queryUsers(@RequestParam(required = false) String username,@RequestParam(required = false) Integer minAge,@RequestParam(required = false) Integer maxAge) {// 方式1:QueryWrapper(字符串字段名,易出错)/*QueryWrapper<User> queryWrapper = new QueryWrapper<>();if (username != null) {queryWrapper.like("username", username); // 模糊查询}if (minAge != null) {queryWrapper.ge("age", minAge); // 大于等于}if (maxAge != null) {queryWrapper.le("age", maxAge); // 小于等于}queryWrapper.orderByDesc("create_time"); // 按创建时间降序*/// 方式2:LambdaQueryWrapper(类型安全,推荐)LambdaQueryWrapper<User> lambdaQuery = new LambdaQueryWrapper<>();if (username != null) {lambdaQuery.like(User::getUsername, username); // 引用方法,避免字段名拼写错误}if (minAge != null) {lambdaQuery.ge(User::getAge, minAge);}if (maxAge != null) {lambdaQuery.le(User::getAge, maxAge);}lambdaQuery.orderByDesc(User::getCreateTime);return userService.list(lambdaQuery);
}

常用条件方法

  • eq:等于(=);
  • ne:不等于(≠);
  • like:模糊查询(%value%);
  • likeLeft:左模糊(%value);
  • likeRight:右模糊(value%);
  • ge:大于等于(≥);
  • le:小于等于(≤);
  • in:包含(in (value1, value2));
  • orderByAsc/orderByDesc:排序。

4.3 分页查询

MyBatisPlus的分页插件可一键实现分页功能,步骤如下:

4.3.1 配置分页插件
package com.example.mp.config;import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class MyBatisPlusConfig {// 注册分页插件@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加分页插件(针对MySQL)interceptor.addInnerInterceptor(new PaginationInnerInterceptor());return interceptor;}
}
4.3.2 实现分页查询
// 分页查询
@GetMapping("/page")
public IPage<User> getUserPage(@RequestParam(defaultValue = "1") Integer pageNum, // 页码(默认1)@RequestParam(defaultValue = "10") Integer pageSize) { // 每页条数(默认10)// 创建分页对象Page<User> page = new Page<>(pageNum, pageSize);// 执行分页查询(支持条件查询)IPage<User> userPage = userService.page(page, new LambdaQueryWrapper<User>().ge(User::getAge, 18)); // 条件:年龄≥18return userPage;
}

返回结果说明

{"records": [{"id": 1, "username": "张三", ...}], // 当前页数据"total": 3, // 总条数"size": 10, // 每页条数"current": 1, // 当前页码"pages": 1 // 总页数
}

4.4 自定义SQL(XML方式)

MyBatisPlus兼容MyBatis的XML方式,适合复杂SQL场景:

4.4.1 在Mapper接口中定义方法
package com.example.mp.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.mp.entity.User;
import java.util.List;public interface UserMapper extends BaseMapper<User> {// 自定义方法:查询指定年龄范围的用户List<User> selectByAgeRange(@Param("minAge") Integer minAge, @Param("maxAge") Integer maxAge);
}
4.4.2 创建XML映射文件

src/main/resources/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.example.mp.mapper.UserMapper"><!-- 自定义查询:根据年龄范围查询 --><select id="selectByAgeRange" resultType="User">SELECT * FROM user WHERE age BETWEEN #{minAge} AND #{maxAge}AND is_deleted = 0</select>
</mapper>
4.4.3 在Service中调用
// 在UserService接口添加方法
List<User> selectByAgeRange(Integer minAge, Integer maxAge);// 在UserServiceImpl实现方法
@Override
public List<User> selectByAgeRange(Integer minAge, Integer maxAge) {return baseMapper.selectByAgeRange(minAge, maxAge);
}// 在Controller中使用
@GetMapping("/age-range")
public List<User> getByAgeRange(Integer minAge, Integer maxAge) {return userService.selectByAgeRange(minAge, maxAge);
}

五、MyBatisPlus高级特性

5.1 代码生成器(AutoGenerator)

AutoGenerator可根据数据库表自动生成实体类、Mapper、Service、Controller等代码,步骤如下:

5.1.1 添加代码生成器依赖
<dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId><version>3.5.3.1</version>
</dependency>
<!-- 模板引擎(默认Velocity) -->
<dependency><groupId>org.apache.velocity</groupId><artifactId>velocity-engine-core</artifactId><version>2.3</version>
</dependency>
5.1.2 编写生成器配置类
package com.example.mp.generator;import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import java.util.Collections;public class CodeGenerator {public static void main(String[] args) {// 数据库连接配置FastAutoGenerator.create("jdbc:mysql://localhost:3306/mp_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai","root", "root")// 全局配置.globalConfig(builder -> {builder.author("开发者") // 设置作者.outputDir(System.getProperty("user.dir") + "/src/main/java") // 输出目录.disableOpenDir(); // 生成后不打开文件夹})// 包配置.packageConfig(builder -> {builder.parent("com.example.mp") // 父包名.moduleName("") // 模块名(无子模块可留空).mapper("mapper") // Mapper包名.service("service") // Service包名.controller("controller") // Controller包名.entity("entity") // 实体类包名.pathInfo(Collections.singletonMap(OutputFile.mapperXml, System.getProperty("user.dir") + "/src/main/resources/mapper")); // MapperXML路径})// 策略配置.strategyConfig(builder -> {builder.addInclude("user") // 需要生成的表名(可多个).addTablePrefix("t_") // 忽略表前缀(如t_user → User)// 实体类策略.entityBuilder().enableLombok() // 启用Lombok.enableTableFieldAnnotation() // 生成字段注解// Controller策略.controllerBuilder().enableRestStyle(); // 生成@RestController}).execute(); // 执行生成}
}

运行CodeGeneratormain方法,即可自动生成全套代码。

5.2 乐观锁插件

乐观锁用于解决并发更新冲突(如秒杀场景),通过版本号控制:

5.2.1 配置乐观锁插件
@Configuration
public class MyBatisPlusConfig {@Beanpublic MybatisPlusInterceptor mybatisPlusInterceptor() {MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();// 添加分页插件interceptor.addInnerInterceptor(new PaginationInnerInterceptor());// 添加乐观锁插件interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());return interceptor;}
}
5.2.2 在实体类添加版本字段
@Data
@TableName("user")
public class User {// ... 其他字段@Version // 标记为乐观锁版本字段private Integer version;
}
5.2.3 使用乐观锁
// 更新时自动校验版本号
@PutMapping("/optimistic")
public String updateWithOptimisticLock(@RequestBody User user) {// 1. 先查询用户(获取当前version)User dbUser = userService.getById(user.getId());if (dbUser == null) {return "用户不存在";}// 2. 设置要更新的字段dbUser.setUsername(user.getUsername());dbUser.setAge(user.getAge());// 3. 执行更新(MP会自动添加WHERE version = ?条件)boolean success = userService.updateById(dbUser);return success ? "更新成功" : "更新失败(可能已被其他线程修改)";
}

六、常见问题与避坑指南

6.1 依赖冲突问题

若同时引入mybatis-plus-boot-startermybatis-spring-boot-starter,会导致依赖冲突。解决方案:只保留mybatis-plus-boot-starter

6.2 逻辑删除失效

原因

  • 未配置@TableLogic注解;
  • 全局配置中logic-delete-field与实体类字段名不一致;
  • 自定义SQL未添加is_deleted = 0条件。

解决方案:确保注解和配置一致,自定义SQL需手动处理逻辑删除。

6.3 分页查询返回总数为0

原因:未配置分页插件或插件顺序错误。

解决方案:在MybatisPlusInterceptor中正确注册PaginationInnerInterceptor

6.4 LambdaQueryWrapper字段引用错误

使用User::getUsername时若报“方法引用错误”,可能是Lombok版本与IDE插件不兼容。解决方案:升级Lombok版本或重新安装IDE插件。

总结

SpringBoot整合MyBatisPlus能显著简化CRUD操作:

  • 无SQL开发:通过BaseMapperIService实现基础CRUD,无需编写SQL;
  • 条件构造器LambdaQueryWrapper替代动态SQL,类型安全且简洁;
  • 丰富插件:分页、乐观锁、逻辑删除等功能一键集成;
  • 代码生成器:自动生成全套代码,减少重复劳动。

实际开发中,建议基础操作使用MyBatisPlus的内置方法,复杂查询结合XML方式,平衡开发效率和灵活性。

若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ

http://www.dtcms.com/a/313436.html

相关文章:

  • Nvidia Orin DK 刷机CUDA TensorRT+硬盘扩容+ROS+Realsense+OpenCV+Ollama+Yolo11 一站式解决方案
  • 从“配置地狱”到“云端乐园”——Nacos 如何成为分布式微服务配置中心的“定海神针”
  • 数组和指针的关系
  • 操作系统——读者写者问题
  • KNX协议介绍
  • Nvidia Orin + RealSense D435i 与3D地图实现导航
  • Ubuntu系统VScode实现opencv(c++)视频的处理与保存
  • [硬件电路-129]:模拟电路 - 继电器的工作原理、关键指标、常用芯片与管脚定义
  • SpringAI的使用
  • Socket编程——TCP协议
  • 从一到无穷大 #51:突破阿姆达尔定律:COZ因果剖析与串行优化八法
  • Java学习第一百零一部分——网关(Gateway)
  • java测试题(ssm框架)
  • 02.Redis 安装
  • MPLS 静态LSP
  • TV电视版软件集合分享
  • 深入理解Java并发编程:原理、实战与最佳实践
  • Redis 7 中的 Set 和 Zset 使用
  • 基于transformer的目标检测——匈牙利匹配算法
  • 深入解析HashMap:原理与性能优化
  • Vim编辑器详解:从入门到高效使用
  • 从零开始的CAD|CAE开发: LBM源码实现分享
  • 编程语言分类
  • JAVAEE--5.多线程之常见的锁策略
  • AI Competitor Intelligence Agent Team
  • 【openlayers框架学习】七:绘制线要素以及点击画线功能
  • 力扣热题100----------141.环形链表
  • 基于BiLSTM+CRF实现NER
  • 【机器人】VLN-R1 微调 | 增强训练 | 连续导航
  • Web3合约ABI,合约地址生成部署调用及创建,连接钱包,基础交易流程