目录
[Spring Boot2](#Spring Boot2)
[Spring Boot3](#Spring Boot3)
[Spring Boot 工程](#Spring Boot 工程)
[Spring 工程](#Spring 工程)
简介
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)确实提供了强大且灵活的功能,用于构建各种数据库查询和更新条件。
- AbstractWrapper
AbstractWrapper 是所有 Wrapper 类的基类,定义了构造查询和更新条件的基础方法和属性,包括字段、值、操作符等。其他具体的 Wrapper 类(如 QueryWrapper、UpdateWrapper、LambdaQueryWrapper 和 LambdaUpdateWrapper)都继承自它。
- 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 表示模糊匹配。
- 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 用于指定需要更新的字段及其新值。
- 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);
- 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 查询
- 资源管理: 使用流式查询时,确保数据库连接在操作完成后被正确关闭,避免连接泄露问题。
- 性能优化: 流式查询适合于大数据量的场景,不适合处理小数据量的查询,因其可能引入不必要的复杂性。
批量操作
批量操作是处理大量数据时的一种高效技术,它通过一次性执行多个数据库操作来提高效率和性能。常见的批量操作包括:
- 数据插入:一次性插入多条记录,减少SQL执行次数,加快数据写入速度。
- 数据更新:同时更新多条记录的特定字段,适用于批量修改数据的场景。
- 数据删除:快速删除多条记录,适合数据清理和用户注销等操作。
功能概览
- 支持版本: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方法参数不一致时的转换处理器
使用步骤
- 创建MybatisBatch实例:绑定数据列表和sqlSessionFactory。
- 创建MybatisBatch.Method实例:确定执行的Mapper类方法。
- 执行操作:将批量参数转换为Mapper方法所需的参数。
- 处理返回值:返回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(防止全表更新与删除):防止全表更新和删除操作,避免误操作。
插件定义顺序
使用多个插件时,需要注意插件的定义顺序以确保插件功能的正常运行。通常的顺序如下:
- 多租户(TenantLineInnerInterceptor)
- 动态表名(DynamicTableNameInnerInterceptor)
- 分页(PaginationInnerInterceptor)
- 乐观锁(OptimisticLockerInnerInterceptor)
- SQL 性能规范(IllegalSQLInnerInterceptor)
- 防止全表更新与删除(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格式返回。