MybatisPlus 快速入门

目录

简介

安装

[Spring Boot2](#Spring Boot2)

[Spring Boot3](#Spring Boot3)

Spring

配置

[Spring Boot 工程](#Spring Boot 工程)

[Spring 工程](#Spring 工程)

常见注解

条件构造器

流式查询

使用示例

批量操作

使用示例

自定义SQL

Service接口

CRUD

扩展功能

代码生成

安装插件

通用枚举

配置枚举处理器

插件功能

配置示例


简介

MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
  • 分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
  • 内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
  • 内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作

安装

Spring Boot2

XML 复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.7</version>
</dependency>

Spring Boot3

XML 复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.7</version>
</dependency>

Spring

XML 复制代码
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus</artifactId>
    <version>3.5.7</version>
</dependency>

注意事项

引入 MyBatis-Plus 之后请不要再次引入 MyBatis 以及 mybatis-spring-boot-starter和MyBatis-Spring,以避免因版本差异导致的问题。

自3.5.4开始,在没有使用mybatis-plus-boot-starter或mybatis-plus-spring-boot3-starter情况下,请自行根据项目情况引入mybatis-spring。

配置

Spring Boot 工程

配置 MapperScan 注解

java 复制代码
@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {

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

}

大多数的配置都有默认值,因此我们都无需配置。但还有一些是没有默认值的,例如:

1、实体类的别名扫描包

2、全局id类型

XML 复制代码
mybatis-plus:
  type-aliases-package: com.itheima.mp.domain.po
  global-config:
    db-config:
      id-type: auto # 全局id类型为自增长

需要注意的是,MyBatisPlus也支持手写SQL的,而mapper文件的读取地址可以自己配置:+

XML 复制代码
mybatis-plus:
  mapper-locations: "classpath*:/mapper/**/*.xml" # Mapper.xml文件地址,当前这个是默认值。

可以看到默认值是classpath*:/mapper/**/*.xml,也就是说我们只要把mapper.xml文件放置这个目录下就一定会被加载。

Spring 工程

配置 MapperScan

XML 复制代码
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="basePackage" value="com.baomidou.mybatisplus.samples.quickstart.mapper"/>
</bean>

调整 SqlSessionFactory 为 MyBatis-Plus 的 SqlSessionFactory

XML 复制代码
<bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
</bean>

常见注解

1、@TableName

用于指定数据库表名。通常与实体类一起使用,用于映射数据库表。

TableName注解除了指定表名以外,还可以指定很多其它属性:

|------------------|------------|----------|---------|---------------------------------------------------------------|
| 属性 | 类型 | 必须指定 | 默认值 | 描述 |
| value | String | 否 | "" | 表名 |
| schema | String | 否 | "" | schema |
| keepGlobalPrefix | boolean | 否 | false | 是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时) |
| resultMap | String | 否 | "" | xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定) |
| autoResultMap | boolean | 否 | false | 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入) |
| excludeProperty | String[] | 否 | {} | 需要排除的属性名 @since 3.3.1 |

2、@TableId

用于标识实体类中的主键字段。可以指定主键的生成策略。

TableId注解支持两个属性:

属性 类型 必须指定 默认值 描述
value String "" 表名
type Enum IdType.NONE 指定主键类型

IdType支持的类型有:

描述
AUTO 数据库 ID 自增
NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUT insert 前自行 set 主键值
ASSIGN_ID 分配 ID(主键类型为 Number(Long 和 Integer)或 String)(since 3.3.0),使用接口IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID 分配 UUID,主键类型为 String(since 3.3.0),使用接口IdentifierGenerator的方法nextUUID(默认 default 方法)
ID_WORKER 分布式全局唯一 ID 长整型类型(please use ASSIGN_ID)
UUID 32 位 UUID 字符串(please use ASSIGN_UUID)
ID_WORKER_STR 分布式全局唯一 ID 字符串类型(please use ASSIGN_ID)

这里比较常见的有三种:

  • AUTO:利用数据库的id自增长
  • INPUT:手动生成id
  • ASSIGN_ID:雪花算法生成Long类型的全局唯一id,这是默认的ID策略

3、@TableField

用于指定实体类字段与数据库表字段的映射关系。它可以用于自定义列名、是否插入、更新等。

一般情况下我们并不需要给字段添加@TableField注解,一些特殊情况除外:

1、成员变量名与数据库字段名不一致

如果实体类中的字段名与数据库表中的列名不一致,可以使用 @TableField 注解来指定数据库中的列名:

java 复制代码
@TableField(value = "db_column_name")
private String entityFieldName;

2、成员变量是以 isXXX 命名

按照 JavaBean 规范,如果字段以 is 开头,MyBatis-Plus 默认会去掉 is 部分来进行映射。如果数据库字段名与去掉 is 后的变量名不一致,需要用 @TableField 指定数据库中的列名:

java 复制代码
@TableField(value = "db_column_name")
private Boolean isActive;

3、成员变量名与数据库字段一致,但与数据库关键字冲突

如果字段名与数据库中的关键字冲突,可以使用反引号 ```` 来处理:

java 复制代码
@TableField(value = "`key`")
private String key;

支持的其它属性如下:

|------------------|------------|--------|-----------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 属性 | 类型 | 必填 | 默认值 | 描述 |
| value | String | 否 | "" | 数据库字段名 |
| exist | boolean | 否 | true | 是否为数据库表字段 |
| condition | String | 否 | "" | 字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考(opens new window) |
| update | String | 否 | "" | 字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性) |
| insertStrategy | Enum | 否 | FieldStrategy.DEFAULT | 举例:NOT_NULL insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>) |
| updateStrategy | Enum | 否 | FieldStrategy.DEFAULT | 举例:IGNORED update table_a set column=#{columnProperty} |
| whereStrategy | Enum | 否 | FieldStrategy.DEFAULT | 举例:NOT_EMPTY where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if> |
| fill | Enum | 否 | FieldFill.DEFAULT | 字段自动填充策略 |
| select | boolean | 否 | true | 是否进行 select 查询 |
| keepGlobalFormat | boolean | 否 | false | 是否保持使用全局的 format 进行处理 |
| jdbcType | JdbcType | 否 | JdbcType.UNDEFINED | JDBC 类型 (该默认值不代表会按照该值生效) |
| typeHandler | TypeHander | 否 | | 类型处理器 (该默认值不代表会按照该值生效) |
| numericScale | String | 否 | "" | 指定小数点后保留的位数 |

条件构造器

MyBatis-Plus 的条件构造器(Wrapper)确实提供了强大且灵活的功能,用于构建各种数据库查询和更新条件。

  1. AbstractWrapper

AbstractWrapper 是所有 Wrapper 类的基类,定义了构造查询和更新条件的基础方法和属性,包括字段、值、操作符等。其他具体的 Wrapper 类(如 QueryWrapper、UpdateWrapper、LambdaQueryWrapper 和 LambdaUpdateWrapper)都继承自它。

  1. QueryWrapper

QueryWrapper 用于构造查询条件,支持多种操作符和逻辑组合。可以通过链式调用添加多个查询条件,并通过 and 和 or 来组合条件。

java 复制代码
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("status", 1)
            .gt("age", 18)
            .or()
            .like("name", "John");

List<User> users = userMapper.selectList(queryWrapper);

在上面的例子中,eq 表示等于,gt 表示大于,or 表示逻辑"或",like 表示模糊匹配。

  1. UpdateWrapper

UpdateWrapper 用于构造更新条件,它允许你在更新数据时指定条件。它的使用方法与 QueryWrapper 类似。

java 复制代码
UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("status", 1)
             .set("age", 30)
             .set("name", "Updated Name");

userMapper.update(null, updateWrapper);

在这个例子中,set 用于指定需要更新的字段及其新值。

  1. LambdaQueryWrapper

LambdaQueryWrapper 允许使用 Lambda 表达式来引用实体类的属性,避免了硬编码字段名的问题,从而提高了代码的可读性和可维护性。

java 复制代码
LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(User::getStatus, 1)
                  .gt(User::getAge, 18)
                  .or()
                  .like(User::getName, "John");

List<User> users = userMapper.selectList(lambdaQueryWrapper);
  1. LambdaUpdateWrapper

LambdaUpdateWrapper 与 LambdaQueryWrapper 类似,但用于构造更新条件。它允许使用 Lambda 表达式来设置更新字段及条件。

java 复制代码
LambdaUpdateWrapper<User> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
lambdaUpdateWrapper.eq(User::getStatus, 1)
                   .set(User::getAge, 30)
                   .set(User::getName, "Updated Name");

userMapper.update(null, lambdaUpdateWrapper);

流式查询

MyBatis-Plus 从 3.5.4 版本开始支持流式查询,这使得在处理大数据量时更加高效。流式查询通过 ResultHandler 接口实现,可以有效地避免将整个结果集加载到内存中,适合用于数据跑批或大规模数据处理的场景。

常用方法

在 ResultHandler 中,可以使用以下方法来处理查询结果:

  • getResultObject(): 获取当前数据库中的每一条记录。
  • getResultCount(): 获取当前处理的结果集条数,每处理一条记录,该计数器会加1,计数从1开始。
  • stop(): 停止继续处理结果集,相当于在循环中使用 break 语句。

使用示例

以下是官网使用流式查询的示例代码,展示了如何结合分页从数据库中拉取数据进行批量处理,以及如何获取表中的所有记录进行处理。

java 复制代码
// 结合分页,按批次从数据库拉取数据出来跑批,例如从数据库获取10万记录,做数据处理
Page<H2User> page = new Page<>(1, 100000);
baseMapper.selectList(page, Wrappers.emptyWrapper(), new ResultHandler<H2User>() {
    int count = 0;
    @Override
    public void handleResult(ResultContext<? extends H2User> resultContext) {
        H2User h2User = resultContext.getResultObject();
        System.out.println("当前处理第" + (++count) + "条记录: " + h2User);
        // 在这里进行你的业务处理,比如分发任务
    }
});

// 从数据库获取表所有记录,做数据处理
baseMapper.selectList(Wrappers.emptyWrapper(), new ResultHandler<H2User>() {
    int count = 0;
    @Override
    public void handleResult(ResultContext<? extends H2User> resultContext) {
        H2User h2User = resultContext.getResultObject();
        System.out.println("当前处理第" + (++count) + "条记录: " + h2User);
        // 在这里进行你的业务处理,比如分发任务
    }
});

注意事项

  • 分页查询与流式查询: 在低版本的 MyBatis-Plus 中,自定义 ResultHandler 结合分页查询可能会出现问题。解决方案是手动关闭 count 查询
  • 资源管理: 使用流式查询时,确保数据库连接在操作完成后被正确关闭,避免连接泄露问题。
  • 性能优化: 流式查询适合于大数据量的场景,不适合处理小数据量的查询,因其可能引入不必要的复杂性。

批量操作

批量操作是处理大量数据时的一种高效技术,它通过一次性执行多个数据库操作来提高效率和性能。常见的批量操作包括:

  1. 数据插入:一次性插入多条记录,减少SQL执行次数,加快数据写入速度。
  2. 数据更新:同时更新多条记录的特定字段,适用于批量修改数据的场景。
  3. 数据删除:快速删除多条记录,适合数据清理和用户注销等操作。

功能概览

  • 支持版本:3.5.4及以上版本
  • 事务控制:需手动管理(默认关闭)
  • 执行结果:返回批量处理结果,帮助判断操作是否成功
  • 数据写入:取决于代码是否正确执行到flushStatements
  • 兼容性:支持Spring和非Spring项目
  • 异常类型:可能会抛出PersistenceException
  • 建议:对于saveOrUpdate方法,建议简单处理新增或更新操作

类结构说明

MybatisBatch<?>

  • 泛型:实际数据类型
  • sqlSessionFactory:通过容器获取,非Spring容器下需手动初始化
  • dataList:批量数据处理列表(不能为空)

MybatisBatch.Method<?>

  • 实际为BatchMethod,用于简化框架内部操作方法的调用
  • 泛型:实际Mapper方法参数类型
  • mapperClass:具体的Mapper类

BatchMethod<?>

  • 泛型:实际Mapper方法参数类型
  • statementId:执行的MappedStatement ID
  • parameterConvert:用于数据类型与Mapper方法参数不一致时的转换处理器

使用步骤

  1. 创建MybatisBatch实例:绑定数据列表和sqlSessionFactory。
  2. 创建MybatisBatch.Method实例:确定执行的Mapper类方法。
  3. 执行操作:将批量参数转换为Mapper方法所需的参数。
  4. 处理返回值:返回List<BatchResult>,每个BatchResult代表一次MappedStatement的操作结果。

返回值说明

  • 返回类型:List<BatchResult>
  • 返回内容:分组存储每次MappedStatement + SQL操作的结果。例如,批量更新时,返回值将根据更新字段的不同分组,显示每组记录的更新情况。

使用示例

execute 方法

execute 方法通常用于直接执行批量操作,例如批量插入或更新。它通过指定的 SQL 语句执行批量处理。在 MyBatis-Plus 中,这通常涉及到使用 SqlSession 执行自定义 SQL。

java 复制代码
public void executeBatch(List<MyEntity> entities) {
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
    try {
        MyMapper mapper = sqlSession.getMapper(MyMapper.class);
        for (MyEntity entity : entities) {
            mapper.insert(entity); // 执行插入操作
        }
        sqlSession.commit(); // 提交事务
    } catch (Exception e) {
        sqlSession.rollback(); // 回滚事务
        throw e;
    } finally {
        sqlSession.close();
    }
}

saveOrUpdate 方法

saveOrUpdate 方法用于处理批量保存或更新操作,自动决定记录是插入还是更新。+

注意:跨sqlSession下需注意缓存和数据感知问题。

java 复制代码
public void saveOrUpdateBatch(List<MyEntity> entities) {
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
    try {
        MyMapper mapper = sqlSession.getMapper(MyMapper.class);
        for (MyEntity entity : entities) {
            if (entity.getId() == null || mapper.selectById(entity.getId()) == null) {
                mapper.insert(entity); // 插入操作
            } else {
                mapper.updateById(entity); // 更新操作
            }
        }
        sqlSession.commit(); // 提交事务
    } catch (Exception e) {
        sqlSession.rollback(); // 回滚事务
        throw e;
    } finally {
        sqlSession.close();
    }
}

事务处理示例

在 MyBatis-Plus 中,事务管理可以通过 Spring 的事务管理器或 MyBatis 的原生事务控制进行。

Spring 事务处理示例:

java 复制代码
@Service
public class MyService {

    @Autowired
    private MyMapper myMapper;

    @Transactional // 事务注解
    public void batchProcess(List<MyEntity> entities) {
        for (MyEntity entity : entities) {
            myMapper.insert(entity); // 执行插入操作
        }
    }
}

手动事务处理示例:

java 复制代码
public void manualTransaction(List<MyEntity> entities) {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        MyMapper mapper = sqlSession.getMapper(MyMapper.class);
        for (MyEntity entity : entities) {
            mapper.insert(entity); // 执行插入操作
        }
        sqlSession.commit(); // 提交事务
    } catch (Exception e) {
        sqlSession.rollback(); // 回滚事务
        throw e;
    } finally {
        sqlSession.close();
    }
}

自定义 SQL

sql

sql 复制代码
-- 1,删除数据库
	drop database if exists test;
-- 2,创建数据库
	create database test;
-- 3,修改数据库编码方式和字符集排列顺序
	alter database test character set utf8 collate utf8_bin;
-- 4,使用数据库
	use test;

-- 创建教师表
CREATE TABLE teacher (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    subject VARCHAR(100) NOT NULL
);

-- 创建班级表
CREATE TABLE class (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    teacher_id INT,
    FOREIGN KEY (teacher_id) REFERENCES teacher(id)
);

-- 创建学生表
CREATE TABLE student (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    age INT NOT NULL,
    class_id INT,
    FOREIGN KEY (class_id) REFERENCES class(id)
);
-- 插入教师数据
INSERT INTO teacher (name, subject) VALUES
('李华', '数学'),
('张伟', '物理'),
('王芳', '历史');

-- 插入班级数据,并关联教师
INSERT INTO class (name, teacher_id) VALUES
('数学101', 1),   -- 由李华教授
('物理101', 2),   -- 由张伟教授
('历史101', 3);   -- 由王芳教授

-- 插入学生数据,并关联班级
INSERT INTO student (name, age, class_id) VALUES
('小明', 15, 1),  -- 在数学101班级
('小红', 16, 1),  -- 在数学101班级
('小刚', 15, 2),  -- 在物理101班级
('小李', 17, 2),  -- 在物理101班级
('小华', 16, 3);  -- 在历史101班级

查询李华教授带的课程,班级,学生数据

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.TeacherMapper">
    <!-- 查询李华教授带的课程、班级和学生数据 -->
    <select id="findTeacherClassesAndStudents" resultType="map">
        SELECT
            t.name AS teacher_name,
            c.name AS class_name,
            s.name AS student_name,
            s.age AS student_age
        FROM teacher t
                 JOIN class c ON t.id = c.teacher_id
                 JOIN student s ON c.id = s.class_id
        WHERE t.name = '李华'
    </select>
</mapper>
java 复制代码
package com.example.demo.mapper;

import com.example.demo.entity.Teacher;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author 
 * @since 2024-09-08
 */
@Mapper
public interface TeacherMapper extends BaseMapper<Teacher> {
    List<Map<String, Object>> findTeacherClassesAndStudents();
}
java 复制代码
package com.example.demo.service.impl;

import com.example.demo.entity.Teacher;
import com.example.demo.mapper.TeacherMapper;
import com.example.demo.service.ITeacherService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 
 * @since 2024-09-08
 */
@Service
public class TeacherServiceImpl extends ServiceImpl<TeacherMapper, Teacher> implements ITeacherService {
    @Autowired
    private TeacherMapper teacherMapper;

    public List<Map<String, Object>> getTeacherClassesAndStudents() {
        return teacherMapper.findTeacherClassesAndStudents();
    }
}
java 复制代码
package com.example.demo.controller;


import com.example.demo.service.impl.TeacherServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author 
 * @since 2024-09-08
 */
@RestController
@RequestMapping("/teacher")
public class TeacherController {

    @Autowired
    private TeacherServiceImpl teacherService;

    @GetMapping("/classes")
    public List<Map<String, Object>> getTeacherClassesAndStudents() {
        return teacherService.getTeacherClassesAndStudents();
    }
}

Service接口

MybatisPlus不仅提供了BaseMapper,还提供了通用的Service接口及默认实现,封装了一些常用的service模板方法。 通用接口为IService,默认实现为ServiceImpl,其中封装的方法可以分为以下几类:

  • save:新增
  • remove:删除
  • update:更新
  • get:查询单个结果
  • list:查询集合结果
  • count:计数
  • page:分页查询

CRUD

我们先俩看下基本的CRUD接口。

新增

  • save - 新增单个元素:用于新增单个记录。它会根据实体类的字段进行插入操作。
  • saveBatch - 批量新增:用于批量新增多条记录。适合在一次操作中插入多个实体对象,提高插入效率。
  • saveOrUpdate - 根据 ID 判断新增或更新:如果实体对象的 ID 存在于数据库中,则执行更新操作;如果 ID 不存在,则执行插入操作。
  • saveOrUpdateBatch - 批量的新增或修改:批量处理实体对象,根据每个对象的 ID 判断是执行插入还是更新操作。

删除:

​​​​​​​

  • removeById - 根据 ID 删除:删除指定 ID 的记录。
  • removeByIds - 批量根据 ID 删除:删除多个指定 ID 的记录。
  • removeByMap - 根据 Map 中的条件删除:根据 Map 中的键值对作为条件进行删除。
  • remove(Wrapper<T>) - 根据 Wrapper 条件删除:使用 Wrapper 对象中定义的条件进行删除。
  • removeBatchByIds 方法已不再支持,建议使用 removeByIds 进行批量删除操作。

修改:

  • updateById - 根据 ID 修改:根据指定 ID 更新记录。需要提供更新后的实体对象。
  • update(Wrapper<T>) - 根据 UpdateWrapper 修改:使用 UpdateWrapper 进行条件更新。需要定义更新的字段和条件。
  • update(T, Wrapper<T>) - 按照实体数据和 Wrapper 修改:根据实体对象中的数据和 Wrapper 中的条件进行更新。实体对象中的字段会被更新到符合 Wrapper 条件的记录中。
  • updateBatchById - 根据 ID 批量修改:根据多个 ID 批量更新记录。实体对象中的数据会更新到对应的 ID 中。

Get:

  • getById - 根据 ID 查询:根据指定 ID 获取一条记录。
  • getOne(Wrapper<T>) - 根据 Wrapper 查询:使用 Wrapper 条件获取一条记录。如果有多条记录符合条件,只会返回其中一条。
  • getBaseMapper - 获取 BaseMapper 实现:获取 Service 内的 BaseMapper 实现,以便进行自定义 SQL 操作或其他特殊操作。

List:

  • listByIds - 根据 ID 批量查询:根据多个 ID 获取对应的记录。
  • list(Wrapper<T>) - 根据 Wrapper 条件查询:使用 Wrapper 条件获取多条记录。
  • list() - 查询所有:获取所有记录。

Count

  • count() - 统计所有记录的数量:统计数据库中所有记录的总数。
  • count(Wrapper<T>) - 统计符合 Wrapper 条件的记录数量:使用 Wrapper 条件统计符合条件的记录数量。

getBaseMapper

getBaseMapper 方法允许在 Service 中直接获取 Mapper 实现,以便执行自定义 SQL 查询或操作。

java 复制代码
TeacherMapper teacherMapper = teacherService.getBaseMapper();
List<Teacher> teachers = teacherMapper.customQueryMethod();

这样,可以在 Mapper 中定义自定义的 SQL 方法,并通过 getBaseMapper 直接调用。

扩展功能

代码生成

MybatisPlus 提供的代码生成器可以大大简化代码编写工作,但使用起来可能有些复杂。推荐的图形化插件能够通过友好的界面完成代码生成,简化了配置和操作流程。这样的工具能有效提升开发效率,减少手动编写基础代码的工作量。

安装插件

在Idea的plugins市场中搜索并安装MyBatisPlus插件:

然后重启你的Idea即可使用。

通用枚举

sql

sql 复制代码
-- 1,删除数据库
	drop database if exists test;
-- 2,创建数据库
	create database test;
-- 3,修改数据库编码方式和字符集排列顺序
	alter database test character set utf8 collate utf8_bin;
-- 4,使用数据库
	use test;

-- 创建教师表
CREATE TABLE teacher (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    subject VARCHAR(100) NOT NULL
);

-- 创建班级表
CREATE TABLE class (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    teacher_id INT,
    FOREIGN KEY (teacher_id) REFERENCES teacher(id)
);

-- 创建学生表
CREATE TABLE student (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    age INT NOT NULL,
    class_id INT,
    gender ENUM('Male', 'Female') NOT NULL,
    FOREIGN KEY (class_id) REFERENCES class(id)
);

-- 插入教师数据
INSERT INTO teacher (name, subject) VALUES
('李华', '数学'),
('张伟', '物理'),
('王芳', '历史');

-- 插入班级数据,并关联教师
INSERT INTO class (name, teacher_id) VALUES
('数学101', 1),
('物理101', 2),
('历史101', 3);

-- 插入学生数据,并关联班级
INSERT INTO student (name, age, class_id, gender) VALUES
('小明', 15, 1, 'Male'),
('小红', 16, 1, 'Female'),
('小刚', 15, 2, 'Male'),
('小李', 17, 2, 'Male'),
('小华', 16, 3, 'Female');

定义通用枚举

java 复制代码
public enum Gender {
    MALE("Male"),
    FEMALE("Female");

    private final String description;

    Gender(String description) {
        this.description = description;
    }

    public String getDescription() {
        return description;
    }
}

假设在 Java 中处理这些数据,可以在实体类中添加枚举字段:

java 复制代码
public class Student {
    private Long id;
    private String name;
    private int age;
    private Long classId;
    private Gender gender;
}

配置枚举处理器

在application.yaml文件中添加配置:

XML 复制代码
mybatis-plus:
  configuration:
    default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler

插件功能

  • PaginationInnerInterceptor(自动分页):自动处理分页查询。
  • TenantLineInnerInterceptor(多租户):实现多租户功能,通过 SQL 查询条件自动添加租户信息。
  • DynamicTableNameInnerInterceptor(动态表名):允许动态更改 SQL 查询中的表名。
  • OptimisticLockerInnerInterceptor(乐观锁):实现乐观锁机制,避免数据的并发更新冲突。
  • IllegalSQLInnerInterceptor(SQL 性能规范):检查 SQL 语句的规范性,避免不合理的 SQL。
  • BlockAttackInnerInterceptor(防止全表更新与删除):防止全表更新和删除操作,避免误操作。

插件定义顺序

使用多个插件时,需要注意插件的定义顺序以确保插件功能的正常运行。通常的顺序如下:

  1. 多租户(TenantLineInnerInterceptor)
  2. 动态表名(DynamicTableNameInnerInterceptor)
  3. 分页(PaginationInnerInterceptor)
  4. 乐观锁(OptimisticLockerInnerInterceptor)
  5. SQL 性能规范(IllegalSQLInnerInterceptor)
  6. 防止全表更新与删除(BlockAttackInnerInterceptor)

配置示例

下面是一个示例配置,演示如何按照顺序注册这些插件:

java 复制代码
package com.example.demo.Config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * MybatisPlus配置类
 * 用于配置MybatisPlus的相关插件
 */
@Configuration
public class MybatisPlusConfig {

    /**
     * 配置MybatisPlus拦截器
     * 拦截器用于处理租户、动态表名、分页、乐观锁、非法SQL和防注入攻击等功能
     *
     * @return 配置好的MybatisPlusInterceptor对象
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加租户拦截器,处理多租户场景下的数据隔离
        interceptor.addInnerInterceptor(new TenantLineInnerInterceptor(/* TenantLineHandler */));
        // 添加动态表名拦截器,支持动态表名
        interceptor.addInnerInterceptor(new DynamicTableNameInnerInterceptor(/* DynamicTableNameHandler */));
        // 添加分页拦截器,实现分页功能
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        // 添加乐观锁拦截器,支持乐观锁机制
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        // 添加非法SQL拦截器,防止非法SQL注入
        interceptor.addInnerInterceptor(new IllegalSQLInnerInterceptor());
        // 添加防注入攻击拦截器,增强SQL安全性
        interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        return interceptor;
    }
}

这里我们以分页插件为里来学习插件的用法。

java 复制代码
package com.example.demo.entity;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * <p>
 * 
 * </p>
 *
 * @author 
 * @since 2024-09-08
 */
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("student")
public class Student implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;

    private String name;

    private Integer age;

    private Integer classId;

    private String gender;
}
java 复制代码
package com.example.demo.mapper;

import com.example.demo.entity.Student;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

/**
 * <p>
 *  Mapper 接口
 * </p>
 *
 * @author 
 * @since 2024-09-08
 */
public interface StudentMapper extends BaseMapper<Student> {

}
java 复制代码
package com.example.demo.controller;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.entity.Student;
import com.example.demo.service.impl.StudentServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author
 * @since 2024-09-08
 */
@RestController
public class StudentController {
    @Autowired
    private StudentServiceImpl studentService;

    @GetMapping("/students")
    public Page<Student> getStudentsByAge(
            @RequestParam int age,
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size) {
        return studentService.getStudentsByAge(age, page, size);
    }
}

启动Spring Boot项目后,访问以下URL进行分页查询:

java 复制代码
http://localhost:8080/students?age=17&page=1&size=10

这将返回年龄为17的学生信息,每页10条记录,并以JSON格式返回。

相关推荐
Q_19284999065 分钟前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟23 分钟前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
ZSYP-S34 分钟前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos37 分钟前
c++------------------函数
开发语言·c++
yuanbenshidiaos41 分钟前
C++----------函数的调用机制
java·c++·算法
程序员_三木1 小时前
Three.js入门-Raycaster鼠标拾取详解与应用
开发语言·javascript·计算机外设·webgl·three.js
是小崔啊1 小时前
开源轮子 - EasyExcel01(核心api)
java·开发语言·开源·excel·阿里巴巴
tianmu_sama1 小时前
[Effective C++]条款38-39 复合和private继承
开发语言·c++
黄公子学安全1 小时前
Java的基础概念(一)
java·开发语言·python
liwulin05061 小时前
【JAVA】Tesseract-OCR截图屏幕指定区域识别0.4.2
java·开发语言·ocr