MybatisPlus 快速入门

news2024/9/20 10:30:26

目录

简介

安装

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格式返回。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2118866.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32 RTC实时时钟

RTC实时时钟 BKP可以在VBAT维持供电时&#xff0c;完成主电源掉电时&#xff0c;保存少量数据的任务。备份寄存器和VBAT引脚同时存在&#xff0c;更多是为了服务RTC的。 目前&#xff0c;Linux、Windows、安卓这些系统&#xff0c;底层的计时系统都是使用的Unix时间戳&#xf…

隔壁老樊2024全国巡回演唱会重磅来袭,首站广州正式官宣!

汹涌人潮将城市填满&#xff0c;斑驳心绪漂浮在时间之隙&#xff0c;当生活的喜悲逐渐演化成歌&#xff0c;天空将自己负载的缄默倾泻&#xff0c;那些或酸涩、或热烈的点滴滑落心海&#xff0c;那层悬挂在「我」与世界分野的无形壁垒&#xff0c;渐也被曙光渗透消融。 提炼生…

vivado 时间汇总报告

步骤7&#xff1a;时间汇总报告 定时路径在时钟元素处开始和结束。输入和输出端口不是顺序的 元素&#xff0c;默认情况下&#xff0c;Vivado时序分析不会对进出I/O端口的路径进行计时 设计&#xff0c;除非指定了输入/输出延迟约束。 在此步骤中&#xff0c;您将在Vivado中生成…

【Vue】关于Vue3的生命周期

目录 Vue3中新增了一个setup生命周期函数&#xff1a;(1) setup执行的时机是在beforeCreate生命周期函数之前执行&#xff0c;在setup函数中是不能通过this来获取实例的&#xff1b;(2) 为了命名的统一性&#xff0c;将beforeDestroy 改名为 beforeUnmount&#xff0c;destroye…

MySQL数据库(初始上)

什么是MySQL MySQL是一个客户端——服务器结构的程序&#xff0c;MySQL的服务器是真正的本体&#xff0c;负责保存和管理数据&#xff0c;数据存储在硬盘上。数据库指的是逻辑上数据的集合&#xff0c;一个MySQL服务器上可以有很多表&#xff0c;把有关连的连到一起就构成了一…

SAP 免费学习网站推荐

1、https://www.guru99.com/ 可以看到有很多的开发语言可以学习。其中就有SAP。 点击SAP菜单后&#xff0c;可以看到每个模块的操作 每个模块下面都有操作的截图&#xff0c;结合翻译软件看的话很容易看懂 2、https://community.sap.com/ 这个是SAP官方的社区&#xff0c…

中国各县域城乡居民收入数据集(2000-2022年)

中国各县域的城乡居民收入是衡量地方经济社会发展水平的关键指标&#xff0c;对于理解区域内的经济活力、居民生活水平以及城乡差距具有重要意义。城镇居民人均可支配收入与农村居民人均可支配收入反映了不同群体的经济状况&#xff0c;前者通常较高&#xff0c;后者则可能受到…

Where I can save my openai-apikey safely for my flutter app

题意&#xff1a;我可以在哪里安全地保存我的 OpenAI API 密钥用于我的 Flutter 应用 问题背景&#xff1a; I am trying using ability of openai for my flutter app, but for now I dont have experience to save apikey safely and efficiently etc. I learned that I can…

【Canvas与电脑桌面壁纸】L形交错十字桌面(1920*1080)

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>L形交错十字桌面</title><style type"text/css"…

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统 在产品将要上线之前&#xff0c;需要制作不同类型格式的根文件系统 在产品研发阶段&#xff0c;我们还是需要使用nfs的方式挂载根文件系统 优点&#xff1a;可以直接在上位机中修改文件系统内容&#xff0c;延长EMMC的寿命 【1】重启上位机nfs服…

业务架构解构与实践

往期回顾 >> CIO要懂业务架构&#xff0c;再谈业务架构的定义与作用&#xff0c;附业务架构教程下载 为什么要坚持先业务后IT&#xff1f;附71页PPT:企业架构及典型设计 为什么说“业务架构师”是ITBP的最佳人选&#xff1f; 业务架构之建模方法 业务架构的伴侣&…

线程安全问题和锁

所属专栏&#xff1a;Java学习 1. 线程的状态 新建&#xff08;New&#xff09;状态&#xff1a;当一个线程对象被创建&#xff0c;但还未调用 start () 方法启动时&#xff0c;处于新建状态。此时线程仅仅是一个 Java 对象&#xff0c;系统尚未为其分配资源。 就绪&am…

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入&#xff08;Embedding&#xff09;方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节&#xff1a;嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以…

Model-based RL动态规划(基于价值、基于策略,泛化迭代)

白盒环境和黑盒环境 白盒环境&#xff1a;知道环境的状态转移函数P(s’|s)或P(s’|s,a)和奖励函数R(s)或R(s,a)&#xff1a;   白盒环境下的学习相当于直接给出了有监督学习的数据分布&#xff08;就是有了目标靶子&#xff09;&#xff0c;不需要采样了&#xff0c;直接最小…

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中&#xff0c;我们经常会遇到这样的情况&#xff1a;一不小心&#xff0c;桌面上的某个重要文件被删除了。这时&#xff0c;大多数人可能会感到惊慌失措&#xff0c;不知所措。 其实&#xff0c;不必过于担心&#xff0c;因为有很多方法可以帮助我们找回…

@开发者极客们,网易2024低代码大赛来啦

极客们&#xff0c;网易云信拍了拍你 9月6日起&#xff0c;2024网易低代码大赛正式开启啦&#xff01; 低代码大赛是由网易主办的权威赛事&#xff0c;鼓励开发者们用低代码开发的方式快速搭建应用&#xff0c;并最终以作品决出优胜。 从2022年11月起&#xff0c;网易低代码大赛…

构建数字产业生态链,共绘数字经济新蓝图

在当今数字化浪潮席卷全球的时代&#xff0c;构建数字产业生态链成为了推动经济发展的关键引擎。数字产业生态链如同一个强大的磁场&#xff0c;吸引着各类创新要素汇聚&#xff0c;共同描绘出数字经济的宏伟新蓝图。 数字产业生态链的核心在于融合与协同。它将软件开发、数据分…

【原创】java+springboot+mysql学生信息管理系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时&#xff0c;发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null&#xff0c;再判断Count。 看了一下Count的源码如下&#xff1a; 1 [__DynamicallyInvokable] 2 public int Count 3 { 4 [__…

做了十几个数字化项目后,我对数字化转型的思考

现在讲数字化转型多是自顶向下视角&#xff0c;但企业仅提战略、目标还不够&#xff0c;必须把任务分配到每个团队及个人每天的工作中&#xff0c;这些工作与员工以前的工作不同&#xff0c;意味着团队和员工也要转型。 企业数字化转型口号再响亮&#xff0c;若一线员工工作内…