MybatisPlus 快速入门

目录

简介

安装

Spring Boot2

Spring Boot3

Spring

配置

Spring Boot 工程

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

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.7</version>
</dependency>

Spring Boot3

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
    <version>3.5.7</version>
</dependency>

Spring

<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 注解

@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类型

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

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

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

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

Spring 工程

配置 MapperScan

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

调整 SqlSessionFactory 为 MyBatis-Plus 的 SqlSessionFactory

<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 注解来指定数据库中的列名:

@TableField(value = "db_column_name")
private String entityFieldName;

2、成员变量是以 isXXX 命名

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

@TableField(value = "db_column_name")
private Boolean isActive;

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

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

@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)都继承自它。

2. QueryWrapper

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

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 表示模糊匹配。 

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

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

userMapper.update(null, updateWrapper);

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

4. LambdaQueryWrapper

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

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);

5. LambdaUpdateWrapper

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

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 语句。

使用示例

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

// 结合分页,按批次从数据库拉取数据出来跑批,例如从数据库获取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。

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下需注意缓存和数据感知问题。

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 事务处理示例:

@Service
public class MyService {

    @Autowired
    private MyMapper myMapper;

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

手动事务处理示例:

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

-- 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 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>
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();
}
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();
    }
}
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 查询或操作。

TeacherMapper teacherMapper = teacherService.getBaseMapper();
List<Teacher> teachers = teacherMapper.customQueryMethod();

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

扩展功能

代码生成

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

安装插件

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

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

通用枚举

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');

定义通用枚举

public enum Gender {
    MALE("Male"),
    FEMALE("Female");

    private final String description;

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

    public String getDescription() {
        return description;
    }
}

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

public class Student {
    private Long id;
    private String name;
    private int age;
    private Long classId;
    private Gender gender;
}

配置枚举处理器

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

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)

配置示例

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

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;
    }
}

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

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;
}
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> {

}
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进行分页查询:

http://localhost:8080/students?age=17&page=1&size=10

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

  • 13
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在奋斗的程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值