Skip to content

一、项目初始化

1. 添加依赖

  • 添加mybatis-plus-boot-starter依赖, 该依赖包包含:
    • mybatis-plus相关依赖
    • mybatis 相关依赖
    • freemarkerthymeleaf 相关依赖
xml
<!-- START: mybatis-plus -->
<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.5.4.1</version>
</dependency>
<!-- END: mybatis-plus -->

2. 创建 Spring MVC 架构模型

  • 新建 entity 模型层
  • 新建 dao 数据访问层
  • 新建 controller 视图控制层

3. 执行数据库脚本

现有一张 User 表,其表结构如下:

idnameageemail
1Jone18test1@baomidou.com
2Jack20test2@baomidou.com
3Tom28test3@baomidou.com
4Sandy21test4@baomidou.com
5Billie24test5@baomidou.com

其对应的数据库 Schema 脚本如下:

sql
DROP TABLE IF EXISTS `user`;

CREATE TABLE `user`
(
  id    BIGINT NOT NULL COMMENT '主键ID',
  name  VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
  age   INT NULL DEFAULT NULL COMMENT '年龄',
  email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
  PRIMARY KEY (id)
);

INSERT INTO `user` (id, name, age, email)
VALUES (1, 'Jone', 18, 'test1@baomidou.com'),
       (2, 'Jack', 20, 'test2@baomidou.com'),
       (3, 'Tom', 28, 'test3@baomidou.com'),
       (4, 'Sandy', 21, 'test4@baomidou.com'),
       (5, 'Billie', 24, 'test5@baomidou.com');

4. 配置

  • 在 pom.xml 添加 MYSQL驱动依赖
xml
<!-- mysql 驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
  • application.yml 配置文件中添加 MySQL 数据库的相关配置:
yaml
# 数据源配置
spring:
  # 配置 MYSQL 连接
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/spring-boot-mybatis-plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    username: root
    password: xxxxxx
  • 在 Spring Boot 启动类中添加 @MapperScan 注解,扫描 Mapper 文件夹:
java
package com.calvin.springboot.example.mybatis.plus;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 应用example02
 *
 * @author calvin
 * @date 2024/01/24
 */
@SpringBootApplication
// @MapperScan 注解,扫描 Mapper
@MapperScan("com.calvin.springboot.example.mybatis.plus.dao")
public class AppExample02 {

    public static void main(String[] args) {
        SpringApplication.run(AppExample02.class, args);
    }

}

5.编码

  • 实体类 User.java(此处使用了 Lombok (opens new window)简化代码)
java
package com.calvin.springboot.example.mybatis.plus.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 用户
 *
 * @author calvin
 * @date 2024/01/24
 */
@Data
@TableName("`user`")
public class User {

  /**
   * id
   */
  private Long id;

  /**
   * 名字。
   */
  private String name;

  /**
   * 年龄
   */
  private Integer age;

  /**
   * 电子邮件
   */
  private String email;

}
  • 编写 dao 包下的 UserMapper接口
java
/**
 * 用户映射器
 *
 * @author Calvin
 * @date 2024/1/24
 * @since v1.0.0
 */
public interface UserMapper extends BaseMapper<User> { 

}
  • 新建 serviceimpl 包, 编写 IUserService接口 和 UserServiceImpl 实现类
java
/* `IUserService` 接口: 继承 IService<User> */
public interface IUserService extends IService<User> { 
}
java
/*  `UserServiceImpl` 接口实现类: 继承 ServiceImpl<UserMapper, User>, 实现 IUserService 接口 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService { 
}
  • 编写 UserController, 实现 CRUD 接口功能
java
/**
 * 用户-控制器
 *
 * @author Calvin
 * @date 2024/1/24
 * @since v1.0.0
 */
@RestController
@RequestMapping("/user")
public class UserController {

  @Resource
  IUserService userService; 

  /**
   * 创建
   *
   * @param user 用户
   * @return {@link Boolean}
   */
  @PostMapping("/create")
  public Boolean create(@RequestBody User user) {
    user.setId(null);
    return userService.save(user); 
  }

  /**
   * 编辑
   *
   * @param user 用户
   * @return {@link Boolean}
   */
  @PutMapping("/edit")
  public Boolean edit(@RequestBody User user) {
    return userService.updateById(user); 
  }

  /**
   * 查询
   *
   * @param id id
   * @return {@link User}
   */
  @GetMapping("/find")
  public User find(@RequestParam("id") Long id) {
    return userService.getById(id); 
  }

  /**
   * 删除
   *
   * @param id id
   * @return {@link Boolean}
   */
  @DeleteMapping("/delete")
  public Boolean delete(@RequestParam("id") Long id) {
    return userService.removeById(id); 
  }

}

6. 视频演示

二、 通用 CRUD

1. 开启控制台日志

yaml
# MyBatis Plus 配置
mybatis-plus:
  configuration:
    # 控制台日志输出
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

# 日志配置
logging:
  level:
    # mybatis 日志级别为 INFO
    mybatis: INFO
  • 日志输出效果
log
JDBC Connection [HikariProxyConnection@1505454100 wrapping com.mysql.cj.jdbc.ConnectionImpl@2ca7eb54] will not be managed by Spring
==>  Preparing: INSERT INTO `user` ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
==> Parameters: 1750042612175224834(Long), Calvin(String), 30(Integer), 1016280226@qq.com(String)
<==    Updates: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@5e461abb]

2. 插入操作

java
package com.calvin.spring.boot.example.mybatis.plus.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 用户
 *
 * @author calvin
 * @date 2024/01/24
 */
@Data
@TableName("`user`")
public class User {

    /**
     * id ID自增
     */
    @TableId(type = IdType.AUTO)  
    private Long id;

    /**
     * 名字。
     */
    private String name;

    /**
     * 年龄
     */
    private Integer age;

    /**
     * 电子邮件
     */
    private String email;

}
  • 源码 IdType 描述
java
/*
 * Copyright (c) 2011-2023, baomidou (jobob@qq.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.baomidou.mybatisplus.annotation;

import lombok.Getter;

/**
 * 生成ID类型枚举类
 *
 * @author hubin
 * @since 2015-11-10
 */
@Getter
public enum IdType {
    /**
     * 数据库ID自增
     * <p>该类型请确保数据库设置了 ID自增 否则无效</p>
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
     */
    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */
    INPUT(2),

    /* 以下2种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 分配ID (主键类型为number或string),
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
     *
     * @since 3.3.0
     */
    ASSIGN_ID(3),
    /**
     * 分配UUID (主键类型为 string)
     * 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
     */
    ASSIGN_UUID(4);

    private final int key;

    IdType(int key) {
        this.key = key;
    }
}
java
package com.calvin.spring.boot.example.mybatis.plus.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

/**
 * 用户
 *
 * @author calvin
 * @date 2024/01/24
 */
@Data
@TableName("`user`")
public class User {

    /**
     * id
     */
    @TableId(type = IdType.AUTO)
    private Long id;

    /**
     * 名字。
     */
    private String name;

    /**
     * 年龄
     */
    @TableField(value = "age") // 表示: 映射该字段名 和数据库表字段名(可以不一致,不一致需要编写数据库表字段名)
    private Integer age;

    /**
     * 电子邮件
     */
    @TableField(select = false) // 表示: select 语句不会拼接查询该字段
    private String email;

    /**
     * 其他
     */
    @TableField(exist = false) // 表示: 可以不存在数据库列中
    private String other;

}
java
// 插入一条记录(选择字段,策略插入)
boolean save(T entity);
// 插入(批量)
boolean saveBatch(Collection<T> entityList);
// 插入(批量)
boolean saveBatch(Collection<T> entityList, int batchSize);
java
// TableId 注解存在更新记录,否插入一条记录
boolean saveOrUpdate(T entity);
// 根据updateWrapper尝试更新,否继续执行saveOrUpdate(T)方法
boolean saveOrUpdate(T entity, Wrapper<T> updateWrapper);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList);
// 批量修改插入
boolean saveOrUpdateBatch(Collection<T> entityList, int batchSize);

3. 更新操作

java
// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper<T> whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);

使用提示:

在调用 updateById 方法前,需要在 T entity(对应的实体类)中的主键属性上加上@TableId注解。 :::

4. 删除操作

java
// 根据 queryWrapper 设置的条件,删除记录
boolean remove(Wrapper<T> queryWrapper);
// 根据 ID 删除
boolean removeById(Serializable id);
// 根据 columnMap 条件,删除记录
boolean removeByMap(Map<String, Object> columnMap);
// 删除(根据ID 批量删除)
boolean removeByIds(Collection<? extends Serializable> idList);

5. 查询操作

java
// 根据 ID 查询
T getById(Serializable id);
// 根据 Wrapper,查询一条记录。结果集,如果是多个会抛出异常,随机取一条加上限制条件 wrapper.last("LIMIT 1")
T getOne(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
T getOne(Wrapper<T> queryWrapper, boolean throwEx);
// 根据 Wrapper,查询一条记录
Map<String, Object> getMap(Wrapper<T> queryWrapper);
// 根据 Wrapper,查询一条记录
<V> V getObj(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
java
// 查询所有
List<T> list();
// 查询列表
List<T> list(Wrapper<T> queryWrapper);
// 查询(根据ID 批量查询)
Collection<T> listByIds(Collection<? extends Serializable> idList);
// 查询(根据 columnMap 条件)
Collection<T> listByMap(Map<String, Object> columnMap);
// 查询所有列表
List<Map<String, Object>> listMaps();
// 查询列表
List<Map<String, Object>> listMaps(Wrapper<T> queryWrapper);
// 查询全部记录
List<Object> listObjs();
// 查询全部记录
<V> List<V> listObjs(Function<? super Object, V> mapper);
// 根据 Wrapper 条件,查询全部记录
List<Object> listObjs(Wrapper<T> queryWrapper);
// 根据 Wrapper 条件,查询全部记录
<V> List<V> listObjs(Wrapper<T> queryWrapper, Function<? super Object, V> mapper);
java
// 无条件分页查询
IPage<T> page(IPage<T> page);
// 条件分页查询
IPage<T> page(IPage<T> page, Wrapper<T> queryWrapper);
// 无条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page);
// 条件分页查询
IPage<Map<String, Object>> pageMaps(IPage<T> page, Wrapper<T> queryWrapper);

6. 条件构造器

详细查看官方文档: https://baomidou.com/pages/10c804/#abstractwrapper

三、插件

  • 如果不使用分页插件,mybatis plus 无法识别你是使用那种数据库的分页方式
  • 新建一个 config 包, 在该包下创建 MyBatisPlusConfiguration
java
package com.calvin.spring.boot.example.mybatis.plus.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Mybatis-Plus 配置
 *
 * @author calvin
 * @date 2024/01/24
 */
@Configuration
@MapperScan("com.calvin.spring.boot.example.mybatis.plus.dao")
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 如果配置多个插件, 切记分页最后添加 (如果有多数据源可以不配具体类型 否则都建议配上具体的DbType)
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}