如何在Spring Boot项目中集成MyBatis-Plus?
一、引入依赖
在项目的 pom.xml 中添加 MyBatis-Plus 启动器和数据库驱动(以 MySQL 为例):
<!-- MyBatis-Plus 启动器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version> <!-- 建议使用最新稳定版 -->
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
二、配置数据源与 MyBatis-Plus
在 application.yml(或 application.properties)中配置数据库连接和 MyBatis-Plus 基础设置:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/your_database?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
username: root
password: your_password
mybatis-plus:
# Mapper XML 文件位置(若有自定义 SQL 需配置)
mapper-locations: classpath*:/mapper/**/*.xml
# 实体类包路径
type-aliases-package: com.example.demo.entity
configuration:
# 开启下划线转驼峰(数据库字段 user_name → 实体类属性 userName)
map-underscore-to-camel-case: true
# 开发环境开启 SQL 日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
三、配置 Mapper 扫描
在 Spring Boot 启动类上添加 @MapperScan 注解,指定 Mapper 接口的包路径:
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.demo.mapper") // 替换为你的 Mapper 接口包路径
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
四、(可选)配置常用插件
若需使用分页、乐观锁等功能,可创建配置类注册插件:
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件(指定数据库类型为 MySQL)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
五、快速验证
创建一个简单的实体类和 Mapper 接口测试集成效果:
- 实体类(
User.java):
```java
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("user") // 对应数据库表名
public class User {
@TableId(type = IdType.ASSIGN_ID) // 雪花算法生成主键
private Long id;
private String name;
private Integer age;
}
2. **Mapper 接口**(`UserMapper.java`):
```java
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 继承 BaseMapper 即可拥有基础 CRUD 能力
}
- 测试调用:
```java
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class DemoApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void testInsert() {
User user = new User();
user.setName("张三");
user.setAge(25);
userMapper.insert(user); // 插入数据
System.out.println("插入成功,ID:" + user.getId());
}
}
# 如何在Spring Boot项目中使用MyBatis-Plus进行数据库操作?
在 Spring Boot 项目中使用 MyBatis-Plus 进行数据库操作,核心是利用其**通用 Mapper**、**条件构造器**和**插件**,无需编写大量 SQL 即可完成 80% 以上的单表操作。以下是完整的操作指南:
### 一、基础 CRUD 操作(通过 BaseMapper)
只要 Mapper 接口继承 `BaseMapper<T>`,即可自动拥有单表的增删改查能力。
#### 1. 定义实体类与 Mapper
- **实体类**(以 `User` 为例):
```java
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@Data
@TableName("user") // 对应数据库表名
public class User {
@TableId(type = IdType.ASSIGN_ID) // 雪花算法生成主键
private Long id;
private String name;
private Integer age;
private String email;
}
Mapper 接口:
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.example.demo.entity.User; import org.apache.ibatis.annotations.Mapper; @Mapper public interface UserMapper extends BaseMapper<User> { // 无需编写方法,继承 BaseMapper 即可 }
2. 调用 CRUD 方法
直接注入 UserMapper 即可使用:
import com.example.demo.entity.User;
import com.example.demo.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
// 1. 插入
public void addUser(User user) {
userMapper.insert(user); // 插入后自动回填主键 ID
}
// 2. 根据 ID 删除
public void deleteUserById(Long id) {
userMapper.deleteById(id);
}
// 3. 根据 ID 更新
public void updateUser(User user) {
userMapper.updateById(user); // 仅更新非空字段
}
// 4. 根据 ID 查询
public User getUserById(Long id) {
return userMapper.selectById(id);
}
// 5. 查询所有
public List<User> getAllUsers() {
return userMapper.selectList(null); // null 表示无条件
}
}
二、条件查询(通过 Wrapper 构造器)
对于复杂查询条件,使用 QueryWrapper 或 LambdaQueryWrapper 构建,避免手写 SQL。
1. 常用条件构造器
QueryWrapper:普通条件构造器,通过字段名(字符串)指定。LambdaQueryWrapper:Lambda 形式,通过方法引用(如User::getName)指定,避免字段名拼写错误(推荐)。
2. 常用条件方法示例
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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
public class UserWrapperTest {
@Autowired
private UserMapper userMapper;
// 1. 普通 QueryWrapper 示例
@Test
public void testQueryWrapper() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("age", 25) // 等于:age = 25
.like("name", "张") // 模糊查询:name LIKE '%张%'
.gt("age", 20) // 大于:age > 20
.orderByDesc("id"); // 按 id 降序
List<User> users = userMapper.selectList(wrapper);
}
// 2. LambdaQueryWrapper 示例(推荐)
@Test
public void testLambdaQueryWrapper() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getAge, 25) // 等于
.like(User::getName, "张") // 模糊查询
.between(User::getAge, 20, 30) // 范围:20 ≤ age ≤ 30
.orderByAsc(User::getCreateTime); // 升序
List<User> users = userMapper.selectList(wrapper);
}
// 3. 组合条件(and/or)
@Test
public void testAndOr() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(User::getAge, 25)
.and(w -> w.like(User::getName, "张").or().like(User::getEmail, "example.com"));
// 等价于:age = 25 AND (name LIKE '%张%' OR email LIKE '%example.com%')
List<User> users = userMapper.selectList(wrapper);
}
}
三、分页查询
需先在配置类中注册 PaginationInnerInterceptor 插件(参考集成步骤),然后通过 Page 对象实现分页。
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class UserPageTest {
@Autowired
private UserMapper userMapper;
@Test
public void testPage() {
// 1. 创建分页对象:当前页(第1页),每页大小(10条)
Page<User> page = new Page<>(1, 10);
// 2. 调用 selectPage 方法,传入分页对象和条件(无条件则传 null)
Page<User> resultPage = userMapper.selectPage(page, null);
// 3. 获取分页结果
System.out.println("总记录数:" + resultPage.getTotal());
System.out.println("总页数:" + resultPage.getPages());
System.out.println("当前页数据:" + resultPage.getRecords());
}
}
四、Service 层封装(可选但推荐)
MyBatis-Plus 提供了 IService<T> 接口和 ServiceImpl<M, T> 实现类,进一步封装业务层操作。
1. 定义 Service 接口与实现
Service 接口:
import com.baomidou.mybatisplus.extension.service.IService; import com.example.demo.entity.User; public interface UserService extends IService<User> { // 可自定义业务方法 }Service 实现类:
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.demo.entity.User; import com.example.demo.mapper.UserMapper; import org.springframework.stereotype.Service; @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { // 继承 ServiceImpl 即可拥有基础业务方法 }
2. 调用 Service 方法
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 批量插入
@PostMapping("/batch")
public void batchAdd(@RequestBody List<User> users) {
userService.saveBatch(users);
}
// 根据 ID 列表查询
@GetMapping("/list")
public List<User> listByIds(@RequestParam List<Long> ids) {
return userService.listByIds(ids);
}
// 批量更新
@PutMapping("/batch")
public void batchUpdate(@RequestBody List<User> users) {
userService.updateBatchById(users);
}
}
五、扩展功能使用
1. 逻辑删除
实体类字段添加
@TableLogic注解:import com.baomidou.mybatisplus.annotation.TableLogic; @Data @TableName("user") public class User { // ... 其他字段 @TableLogic private Integer deleted; // 0:未删除,1:已删除 }- 调用
deleteById时,实际执行的是UPDATE user SET deleted=1 WHERE id=?,查询时自动过滤deleted=1的数据。
2. 乐观锁
实体类字段添加
@Version注解:import com.baomidou.mybatisplus.annotation.Version; @Data @TableName("user") public class User { // ... 其他字段 @Version private Integer version; // 版本号,初始值为 1 }- 更新时需传入
version字段,若版本号不匹配则更新失败:User user = userMapper.selectById(1L); user.setName("李四"); userMapper.updateById(user); // 执行时会自动检查 version
六、自定义 SQL(复杂查询场景)
若需编写复杂 SQL,可结合 MyBatis-Plus 的条件构造器使用。
1. Mapper 接口定义方法
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Param;
public interface UserMapper extends BaseMapper<User> {
// 自定义分页查询方法
IPage<User> selectUserPageByCondition(Page<User> page, @Param("name") String name);
}
2. 编写 XML 文件
在 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.demo.mapper.UserMapper">
<select id="selectUserPageByCondition" resultType="com.example.demo.entity.User">
SELECT * FROM user
<where>
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
</where>
</select>
</mapper>
3. 调用自定义方法
Page<User> page = new Page<>(1, 10);
IPage<User> resultPage = userMapper.selectUserPageByCondition(page, "张");
MyBatis-Plus(完整+可运行)CRUD项目代码示例
第一部分:完整 CRUD 项目代码示例
我们以「用户管理」为核心场景,覆盖实体映射、自动填充、逻辑删除、乐观锁、分页查询、Service 层封装等核心功能。
1. 数据库初始化脚本
先创建数据库和表(包含用户表 user,覆盖所有核心字段):
CREATE DATABASE IF NOT EXISTS mybatis_plus_demo DEFAULT CHARSET utf8mb4;
USE mybatis_plus_demo;
-- 用户表
CREATE TABLE `user` (
`id` BIGINT(20) NOT NULL COMMENT '主键ID',
`name` VARCHAR(30) DEFAULT NULL COMMENT '姓名',
`age` INT(11) DEFAULT NULL COMMENT '年龄',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
`update_time` DATETIME DEFAULT NULL COMMENT '更新时间',
`deleted` TINYINT(1) DEFAULT '0' COMMENT '逻辑删除(0:未删除,1:已删除)',
`version` INT(11) DEFAULT '1' COMMENT '乐观锁版本号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
2. 项目依赖(pom.xml)
使用 Spring Boot 2.7.x + MyBatis-Plus 3.5.5(稳定兼容组合):
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.18</version>
<relativePath/>
</parent>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis-Plus 启动器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.5</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
<!-- Lombok(简化实体类) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3. 项目配置(application.yml)
配置数据库连接、MyBatis-Plus 基础设置和 SQL 日志:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
username: root
password: your_password # 替换为你的数据库密码
mybatis-plus:
mapper-locations: classpath*:/mapper/**/*.xml # Mapper XML 文件位置
type-aliases-package: com.example.demo.entity # 实体类包路径
global-config:
db-config:
id-type: assign_id # 全局主键策略:雪花算法
logic-delete-field: deleted # 全局逻辑删除字段
logic-delete-value: 1 # 逻辑删除值
logic-not-delete-value: 0 # 逻辑未删除值
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开发环境开启 SQL 日志
4. 核心代码实现
(1)实体类(User.java)
包含主键、自动填充、逻辑删除、乐观锁等注解:
package com.example.demo.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 name;
private Integer age;
private String email;
@TableField(fill = FieldFill.INSERT) // 插入时自动填充
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) // 插入和更新时自动填充
private LocalDateTime updateTime;
@TableLogic // 逻辑删除字段
private Integer deleted;
@Version // 乐观锁版本号
private Integer version;
}
(2)自动填充处理器(MyMetaObjectHandler.java)
实现 MetaObjectHandler 接口,自动设置创建时间和更新时间:
package com.example.demo.handler;
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) {
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
(3)MyBatis-Plus 配置类(MybatisPlusConfig.java)
注册分页插件和乐观锁插件:
package com.example.demo.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); // 分页插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor()); // 乐观锁插件
return interceptor;
}
}
(4)Mapper 接口(UserMapper.java)
继承 BaseMapper 即可拥有基础 CRUD 能力:
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.demo.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 无需编写方法,后续复杂查询可在此扩展
}
(5)Service 层
Service 接口(UserService.java):
package com.example.demo.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.demo.entity.User; public interface UserService extends IService<User> { // 可在此定义自定义业务方法 }Service 实现类(UserServiceImpl.java):
package com.example.demo.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.demo.entity.User; import com.example.demo.mapper.UserMapper; import com.example.demo.service.UserService; import org.springframework.stereotype.Service; @Service public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { // 继承 ServiceImpl 即可拥有基础业务方法 }
(6)Controller 层(UserController.java)
提供 RESTful 接口,演示完整 CRUD 和分页查询:
package com.example.demo.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
// 1. 新增用户
@PostMapping
public String addUser(@RequestBody User user) {
boolean success = userService.save(user);
return success ? "新增成功,ID:" + user.getId() : "新增失败";
}
// 2. 根据 ID 删除用户(逻辑删除)
@DeleteMapping("/{id}")
public String deleteUser(@PathVariable Long id) {
boolean success = userService.removeById(id);
return success ? "删除成功" : "删除失败";
}
// 3. 根据 ID 更新用户(乐观锁)
@PutMapping
public String updateUser(@RequestBody User user) {
boolean success = userService.updateById(user);
return success ? "更新成功" : "更新失败(版本号不匹配)";
}
// 4. 根据 ID 查询用户
@GetMapping("/{id}")
public User getUserById(@PathVariable Long id) {
return userService.getById(id);
}
// 5. 条件查询用户列表
@GetMapping("/list")
public List<User> listUsers(@RequestParam(required = false) String name,
@RequestParam(required = false) Integer minAge) {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.like(name != null, User::getName, name) // 模糊查询姓名
.ge(minAge != null, User::getAge, minAge); // 年龄大于等于 minAge
return userService.list(wrapper);
}
// 6. 分页查询用户
@GetMapping("/page")
public Page<User> pageUsers(@RequestParam(defaultValue = "1") Integer current,
@RequestParam(defaultValue = "10") Integer size) {
Page<User> page = new Page<>(current, size);
return userService.page(page, null); // null 表示无条件
}
// 7. 批量新增用户
@PostMapping("/batch")
public String batchAddUsers(@RequestBody List<User> users) {
boolean success = userService.saveBatch(users);
return success ? "批量新增成功" : "批量新增失败";
}
}
(7)Spring Boot 启动类(DemoApplication.java)
添加 @MapperScan 注解扫描 Mapper 接口:
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.example.demo.mapper") // 扫描 Mapper 接口包路径
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
5. 快速测试
启动项目后,使用 Postman 或 curl 测试接口:
- 新增用户:POST
http://localhost:8080/user,Body 传 JSON:{ "name": "张三", "age": 25, "email": "zhangsan@example.com"} - 分页查询:GET
http://localhost:8080/user/page?current=1&size=10 - 条件查询:GET
http://localhost:8080/user/list?name=张&minAge=20
第二部分:复杂查询场景最佳实践
针对多表关联、动态 SQL、批量操作优化等复杂场景,以下是 MyBatis-Plus 的最佳实践方案。
场景 1:多表关联查询(用户 + 订单)
假设我们有一个订单表 order,需要查询「用户及其订单列表」,MyBatis-Plus 推荐结合自定义 XML 实现。
(1)数据库表扩展(订单表)
CREATE TABLE `order` (
`id` BIGINT(20) NOT NULL COMMENT '主键ID',
`user_id` BIGINT(20) NOT NULL COMMENT '用户ID',
`order_no` VARCHAR(50) DEFAULT NULL COMMENT '订单号',
`amount` DECIMAL(10,2) DEFAULT NULL COMMENT '订单金额',
`create_time` DATETIME DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
(2)订单实体类(Order.java)
package com.example.demo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@TableName("order")
public class Order {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private Long userId;
private String orderNo;
private BigDecimal amount;
private LocalDateTime createTime;
}
(3)自定义 VO(UserOrderVO.java)
用于接收关联查询结果:
package com.example.demo.vo;
import com.example.demo.entity.Order;
import com.example.demo.entity.User;
import lombok.Data;
import java.util.List;
@Data
public class UserOrderVO extends User {
private List<Order> orderList; // 用户的订单列表
}
(4)UserMapper 扩展方法
package com.example.demo.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.User;
import com.example.demo.vo.UserOrderVO;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface UserMapper extends BaseMapper<User> {
// 自定义关联分页查询:查询用户及其订单列表
IPage<UserOrderVO> selectUserOrderPage(Page<UserOrderVO> page, @Param("name") String name);
}
(5)编写 UserMapper.xml
在 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.demo.mapper.UserMapper">
<resultMap id="UserOrderVOMap" type="com.example.demo.vo.UserOrderVO">
<!-- 映射用户基本信息 -->
<id column="user_id" property="id"/>
<result column="user_name" property="name"/>
<result column="user_age" property="age"/>
<!-- 映射订单列表(一对多) -->
<collection property="orderList" ofType="com.example.demo.entity.Order">
<id column="order_id" property="id"/>
<result column="order_no" property="orderNo"/>
<result column="order_amount" property="amount"/>
</collection>
</resultMap>
<select id="selectUserOrderPage" resultMap="UserOrderVOMap">
SELECT
u.id AS user_id,
u.name AS user_name,
u.age AS user_age,
o.id AS order_id,
o.order_no,
o.amount AS order_amount
FROM user u
LEFT JOIN `order` o ON u.id = o.user_id
<where>
u.deleted = 0
<if test="name != null and name != ''">
AND u.name LIKE CONCAT('%', #{name}, '%')
</if>
</where>
</select>
</mapper>
(6)调用关联查询方法
@Autowired
private UserMapper userMapper;
@Test
public void testUserOrderPage() {
Page<UserOrderVO> page = new Page<>(1, 10);
IPage<UserOrderVO> resultPage = userMapper.selectUserOrderPage(page, "张");
System.out.println("总记录数:" + resultPage.getTotal());
System.out.println("用户订单列表:" + resultPage.getRecords());
}
场景 2:动态 SQL 优化(复杂条件组合)
对于多条件动态组合的查询,推荐使用 LambdaQueryWrapper 的 nested、and、or 方法,避免拼接 SQL 字符串。
@Test
public void testDynamicQuery() {
String name = "张";
Integer minAge = 20;
Integer maxAge = 30;
String email = "example.com";
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.nested(w -> w.like(name != null, User::getName, name)
.or()
.like(email != null, User::getEmail, email))
.and(w -> w.ge(minAge != null, User::getAge, minAge)
.le(maxAge != null, User::getAge, maxAge))
.orderByDesc(User::getCreateTime);
List<User> users = userMapper.selectList(wrapper);
// 等价于:WHERE (name LIKE '%张%' OR email LIKE '%example.com%') AND (age >= 20 AND age <= 30)
}
场景 3:批量操作优化(性能提升)
MyBatis-Plus 提供的 saveBatch 方法默认是逐条插入,若需提升性能,可通过rewriteBatchedStatements 参数开启 MySQL 批量插入优化。
(1)修改数据库连接 URL
在 application.yml 中添加 rewriteBatchedStatements=true:
spring:
datasource:
url: jdbc:mysql://localhost:3306/mybatis_plus_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true
(2)调整批量插入批次大小
saveBatch 方法默认批次大小为 1000,可通过第二个参数调整:
@Autowired
private UserService userService;
@Test
public void testBatchSaveOptimized() {
List<User> users = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
User user = new User();
user.setName("用户" + i);
user.setAge(20 + i % 30);
user.setEmail("user" + i + "@example.com");
users.add(user);
}
// 批次大小调整为 500(根据实际情况调整)
userService.saveBatch(users, 500);
}
第三部分:项目运行与调试建议
- SQL 日志:开发环境务必开启
log-impl,方便查看执行的 SQL 语句。 - 代码生成器:若需快速生成 Entity、Mapper、Service、Controller,可使用 MyBatis-Plus 官方代码生成器(引入
mybatis-plus-generator依赖)。 - 性能监控:生产环境可结合 P6Spy 等工具监控 SQL 执行性能。