【MyBatis-Plus】Spring Boot + MyBatis-Plus 进行各种数据库操作(附完整 CRUD 项目代码示例)

如何在Spring Boot项目中集成MyBatis-Plus?

一、引入依赖

在项目的 pom.xml 中添加 MyBatis-Plus 启动器和数据库驱动(以 MySQL 为例):

xml 复制代码
<!-- 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 基础设置:

yaml 复制代码
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 接口的包路径:

java 复制代码
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);
    }
}

四、(可选)配置常用插件

若需使用分页、乐观锁等功能,可创建配置类注册插件:

java 复制代码
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 接口测试集成效果:

  1. 实体类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;
}
  1. 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 能力
}
  1. 测试调用
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 接口

    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 即可
    }
2. 调用 CRUD 方法

直接注入 UserMapper 即可使用:

java 复制代码
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 构造器)

对于复杂查询条件,使用 QueryWrapperLambdaQueryWrapper 构建,避免手写 SQL。

1. 常用条件构造器
  • QueryWrapper:普通条件构造器,通过字段名(字符串)指定。
  • LambdaQueryWrapper :Lambda 形式,通过方法引用(如 User::getName)指定,避免字段名拼写错误(推荐)。
2. 常用条件方法示例
java 复制代码
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 对象实现分页。

java 复制代码
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 接口

    java 复制代码
    import com.baomidou.mybatisplus.extension.service.IService;
    import com.example.demo.entity.User;
    
    public interface UserService extends IService<User> {
        // 可自定义业务方法
    }
  • Service 实现类

    java 复制代码
    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 方法
java 复制代码
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 注解:

    java 复制代码
    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 注解:

    java 复制代码
    import com.baomidou.mybatisplus.annotation.Version;
    
    @Data
    @TableName("user")
    public class User {
        // ... 其他字段
        @Version
        private Integer version; // 版本号,初始值为 1
    }
  • 更新时需传入 version 字段,若版本号不匹配则更新失败:

    java 复制代码
    User user = userMapper.selectById(1L);
    user.setName("李四");
    userMapper.updateById(user); // 执行时会自动检查 version

六、自定义 SQL(复杂查询场景)

若需编写复杂 SQL,可结合 MyBatis-Plus 的条件构造器使用。

1. Mapper 接口定义方法
java 复制代码
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 复制代码
<?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. 调用自定义方法
java 复制代码
Page<User> page = new Page<>(1, 10);
IPage<User> resultPage = userMapper.selectUserPageByCondition(page, "张");

MyBatis-Plus(完整+可运行)CRUD项目代码示例

第一部分:完整 CRUD 项目代码示例

我们以「用户管理」为核心场景,覆盖实体映射、自动填充、逻辑删除、乐观锁、分页查询、Service 层封装等核心功能。

1. 数据库初始化脚本

先创建数据库和表(包含用户表 user,覆盖所有核心字段):

sql 复制代码
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(稳定兼容组合):

xml 复制代码
<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 日志:

yaml 复制代码
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)

包含主键、自动填充、逻辑删除、乐观锁等注解:

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 接口,自动设置创建时间和更新时间:

java 复制代码
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)

注册分页插件和乐观锁插件:

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 能力:

java 复制代码
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)

    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)

    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 和分页查询:

java 复制代码
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 接口:

java 复制代码
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:

    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)数据库表扩展(订单表)
sql 复制代码
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)
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)

用于接收关联查询结果:

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 扩展方法
java 复制代码
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 复制代码
<?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)调用关联查询方法
java 复制代码
@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 优化(复杂条件组合)

对于多条件动态组合 的查询,推荐使用 LambdaQueryWrappernestedandor 方法,避免拼接 SQL 字符串。

java 复制代码
@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

yaml 复制代码
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis_plus_demo?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true
(2)调整批量插入批次大小

saveBatch 方法默认批次大小为 1000,可通过第二个参数调整:

java 复制代码
@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);
}

第三部分:项目运行与调试建议

  1. SQL 日志 :开发环境务必开启 log-impl,方便查看执行的 SQL 语句。
  2. 代码生成器 :若需快速生成 Entity、Mapper、Service、Controller,可使用 MyBatis-Plus 官方代码生成器(引入 mybatis-plus-generator 依赖)。
  3. 性能监控:生产环境可结合 P6Spy 等工具监控 SQL 执行性能。
相关推荐
如意机反光镜裸2 小时前
excel怎么快速导入oracle
数据库·oracle·excel
卤炖阑尾炎2 小时前
MySQL 数据库操作从入门到精通
数据库·mysql
茶本无香2 小时前
Greenplum全面解析:架构、优缺点与同类产品对比
数据库
light blue bird2 小时前
MES/ERP的Web多页签报表系统
数据库·node.js·ai大数据·mes/erp·web报表
九章-2 小时前
医疗系统数据库选型技术指南:从合规性到高性能的全方位考量
数据库·信创·医疗信创
Predestination王瀞潞2 小时前
4.1.1 存储->数据库:MongoDB
数据库·mongodb
JZC_xiaozhong2 小时前
ERP与MES制造数据同步:痛点破解与高效落地实践
大数据·数据库·制造·数据传输·数据孤岛解决方案·数据集成与应用集成·异构数据整合
尽兴-2 小时前
超越缓存:Redis Stack 如何将 Redis 打造成全能实时数据平台
数据库·redis·缓存·redis stack
一个有温度的技术博主2 小时前
Redis系列七:Java客户端Jedis的入门
java·数据库·redis