【MyBatis Plus】MyBatis Plus框架
一.基础内容
1.1MyBatis Plus是国产的工具,IDEA不支持
MyBatis Plus是国产的工具,IDEA不支持,我们要手动导包。MyBatis Plus是包含了MyBatis的,所以,我们创建项目的时候,不要勾选MyBatis否则,会导致jar包冲突,引发错误。

1.2引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.2</version>
</dependency>
1.3BaseMapper提供的方法
1.3.1code
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.baomidou.mybatisplus.core.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.exceptions.TooManyResultsException;
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteById(T entity);
default int deleteByMap(Map<String, Object> columnMap) {
QueryWrapper<T> qw = Wrappers.query();
return this.delete((Wrapper)qw.allEq(columnMap));
}
int delete(@Param("ew") Wrapper<T> queryWrapper);
int deleteBatchIds(@Param("coll") Collection<?> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
default List<T> selectByMap(Map<String, Object> columnMap) {
QueryWrapper<T> qw = Wrappers.query();
return this.selectList((Wrapper)qw.allEq(columnMap));
}
default T selectOne(@Param("ew") Wrapper<T> queryWrapper) {
return (T)this.selectOne(queryWrapper, true);
}
default T selectOne(@Param("ew") Wrapper<T> queryWrapper, boolean throwEx) {
List<T> list = this.selectList(queryWrapper);
int size = list.size();
if (size == 1) {
return (T)list.get(0);
} else if (size > 1) {
if (throwEx) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return (T)list.get(0);
}
} else {
return null;
}
}
default boolean exists(Wrapper<T> queryWrapper) {
Long count = this.selectCount(queryWrapper);
return null != count && count > 0L;
}
Long selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(IPage<T> page, @Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(IPage<? extends Map<String, Object>> page, @Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
default <P extends IPage<T>> P selectPage(P page, @Param("ew") Wrapper<T> queryWrapper) {
List<T> list = this.selectList(page, queryWrapper);
page.setRecords(list);
return page;
}
default <P extends IPage<Map<String, Object>>> P selectMapsPage(P page, @Param("ew") Wrapper<T> queryWrapper) {
List<Map<String, Object>> list = this.selectMaps(page, queryWrapper);
page.setRecords(list);
return page;
}
}
1.3.2方法解释
-
insert(T entity)-
作用:新增单条老虎数据
-
参数:entity 为待新增的 Tiger 对象,需封装 tigerName/tigerAge/tigerSalary 等字段值
-
特点:自动生成插入 SQL,支持 tiger_id 主键自增(需实体类 @TableId 配置 type=AUTO)
-
示例:
Tiger tiger = new Tiger(); tiger.setTigerName("孙虎"); tiger.setTigerAge(2); tiger.setTigerSalary(300.50); tigerMapper.insert(tiger); // 插入后自动回填tiger_id
-
-
deleteById(Serializable id)-
作用:根据老虎 ID(主键)删除单条数据
-
参数:id 为 tiger_id 值(Integer 类型,需与实体类主键类型一致)
-
特点:仅支持主键删除,无需编写 delete SQL
-
示例:
tigerMapper.deleteById(1); // 删除tiger_id=1的老虎数据
-
-
deleteByMap(Map<String, Object> columnMap)-
作用:按多字段等值匹配删除老虎数据
-
参数:columnMap 的 key 为数据库字段名(如 tiger_name),value 为匹配值
-
特点:仅支持等值条件,不支持模糊、范围等复杂条件
-
示例:
Map<String, Object> map = new HashMap<>(); map.put("tiger_name", "李虎"); // 数据库字段名 map.put("tiger_age", 3); tigerMapper.deleteByMap(map); // 删除名称为李虎且年龄为3的老虎
-
-
updateById(T entity)-
作用:根据老虎 ID(主键)更新数据
-
参数:entity 需封装 tiger_id(主键)和待更新的字段值(非 null 字段才会更新)
-
特点:自动定位主键对应的记录,仅更新非 null 字段
-
示例:
Tiger tiger = new Tiger(); tiger.setTigerId(1); // 必须指定主键 tiger.setTigerSalary(600.00); // 仅更新薪资字段 tigerMapper.updateById(tiger);
-
-
update(T entity, Wrapper<T> updateWrapper)-
作用:按条件更新老虎数据
-
参数:entity 封装待更新字段值,updateWrapper 封装更新条件(如模糊、范围)
-
特点:支持复杂更新条件,避免手动拼接 SQL
-
示例:
Tiger tiger = new Tiger(); tiger.setTigerSalary(800.00); // 待更新的薪资 // 条件:年龄大于5的老虎 UpdateWrapper<Tiger> wrapper = new UpdateWrapper<>(); wrapper.gt("tiger_age", 5); tigerMapper.update(tiger, wrapper);
-
-
selectById(Serializable id)-
作用:根据老虎 ID(主键)查询单条数据
-
参数:id 为 tiger_id 值(Integer 类型)
-
返回值:匹配的 Tiger 对象,无数据则返回 null
-
示例:
Tiger tiger = tigerMapper.selectById(1); // 查询tiger_id=1的老虎
-
-
selectList(Wrapper<T> queryWrapper)-
作用:按条件查询多条老虎数据
-
参数:queryWrapper 为查询条件封装器(传 null 则查询全表)
-
返回值:匹配的 Tiger 对象列表,支持等值、模糊、排序等多类条件
-
示例:
// 无条件查询全表 List<Tiger> list = tigerMapper.selectList(null); // 带条件:薪资大于200的老虎,按年龄降序 QueryWrapper<Tiger> wrapper = new QueryWrapper<>(); wrapper.gt("tiger_salary", 200).orderByDesc("tiger_age"); List<Tiger> list2 = tigerMapper.selectList(wrapper);
-
核心说明:
-
deleteById/selectById的参数类型为 Integer(匹配 Tiger 实体的 tigerId 类型),需与 t_tiger 表的 tiger_id(INT 类型)一致; -
deleteByMap的 key 必须是数据库字段名(如 tiger_name),而非实体类属性名(tigerName); -
所有方法无需手动编写 XML 或注解 SQL,MyBatis-Plus 自动生成适配 t_tiger 表的 SQL。
1.4 IService<T>接口和ServiceImpl实现类
1.4.1语法

1.4.2ServiceImpl核心方法
-
save(T entity)-
作用:新增单条老虎数据(底层调用 BaseMapper.insert)
-
参数:entity 为待新增的 Tiger 对象
-
特点:方法名贴合业务语义,与 Mapper 层 insert 做区分
-
示例:
Tiger tiger = new Tiger(); tiger.setTigerName("周虎"); tiger.setTigerAge(4); tiger.setTigerSalary(700.00); tigerService.save(tiger);
-
-
removeById(Serializable id)-
作用:根据老虎 ID 删除单条数据(底层调用 BaseMapper.deleteById)
-
参数:id 为 tiger_id 值(Integer 类型)
-
特点:方法名用 remove,更符合业务层 “删除” 语义
-
示例:
tigerService.removeById(2); // 删除tiger_id=2的老虎
-
-
removeByMap(Map<String, Object> columnMap)-
作用:按多字段等值匹配删除老虎数据(底层调用 BaseMapper.deleteByMap)
-
参数:columnMap 的 key 为数据库字段名(如 tiger_age),value 为匹配值
-
示例:
Map<String, Object> map = new HashMap<>(); map.put("tiger_age", 7); tigerService.removeByMap(map); // 删除年龄为7的老虎
-
-
updateById(T entity)-
作用:根据老虎 ID 更新数据(底层调用 BaseMapper.updateById)
-
参数:entity 需封装 tiger_id 和待更新字段值
-
示例:
Tiger tiger = new Tiger(); tiger.setTigerId(3); tiger.setTigerName("张虎-更新"); tigerService.updateById(tiger);
-
-
updateBatchById(Collection<T> entityList):可以多一个参数指定更新多少参数-
作用:按主键批量更新老虎数据
-
参数:entityList 为待更新的 Tiger 对象集合
-
特点:底层分批执行 updateById,默认批次大小 1000,可自定义
-
示例:
List<Tiger> list = new ArrayList<>(); // 第一条更新数据 Tiger t1 = new Tiger(); t1.setTigerId(1); t1.setTigerSalary(550.00); // 第二条更新数据 Tiger t2 = new Tiger(); t2.setTigerId(2); t2.setTigerSalary(850.00); list.add(t1); list.add(t2); tigerService.updateBatchById(list); // 批量更新 // 自定义批次大小(如500) // tigerService.updateBatchById(list, 500);
-
-
getById(Serializable id)-
作用:根据老虎 ID 查询单条数据(底层调用 BaseMapper.selectById)
-
参数:id 为 tiger_id 值(Integer 类型)
-
返回值:匹配的 Tiger 对象,无数据则返回 null
-
特点:方法名用 get,贴合业务层 “查询单行” 语义
-
示例:
Tiger tiger = tigerService.getById(3); // 查询tiger_id=3的老虎
-
-
list(Wrapper<T> queryWrapper):Lambda查询-
作用:按条件查询多条老虎数据(底层调用 BaseMapper.selectList)
-
参数:queryWrapper 为查询条件封装器(传 null 则查询全表),支持 LambdaQueryWrapper 避免硬编码字段名
-
返回值:匹配的 Tiger 对象列表
-
示例:
// 无条件查询全表 List<Tiger> allTigers = tigerService.list(null); // Lambda条件:薪资大于500且年龄小于6的老虎 LambdaQueryWrapper<Tiger> lambdaWrapper = new LambdaQueryWrapper<>(); lambdaWrapper.gt(Tiger::getTigerSalary, 500).lt(Tiger::getTigerAge, 6); List<Tiger> list = tigerService.list(lambdaWrapper);
-
-
page(IPage<T> page, Wrapper<T> queryWrapper):分页查询-
作用:分页查询老虎数据
-
参数:page 指定分页参数(页码、页大小),queryWrapper 为查询条件
-
返回值:IPage 对象(含当前页数据、总条数、总页数等分页信息)
-
特点:补充 Mapper 层缺失的分页能力,适配业务层分页需求
-
示例:
// 分页参数:第1页,每页3条 IPage<Tiger> page = new Page<>(1, 3); // 条件:薪资大于200 QueryWrapper<Tiger> wrapper = new QueryWrapper<>(); wrapper.gt("tiger_salary", 200); // 分页查询 IPage<Tiger> tigerPage = tigerService.page(page, wrapper); // 获取分页结果 System.out.println("总条数:" + tigerPage.getTotal()); System.out.println("总页数:" + tigerPage.getPages()); System.out.println("当前页数据:" + tigerPage.getRecords());
-
1.5Mapper类和LambdaWrapper
【MyBatis Plus】Wrapper接口-CSDN博客
1.6动态条件控制(基于Wrapper)
// 动态参数(可能为null)
String tigerName = "虎";
Integer minSalary = 300;
LambdaQueryWrapper<Tiger> wrapper = Wrappers.lambdaQuery();
// 仅当tigerName非null时,拼接“tiger_name LIKE '%虎%'”
wrapper.like(tigerName != null, Tiger::getTigerName, tigerName);
// 仅当minSalary非null时,拼接“tiger_salary > 300”
wrapper.gt(minSalary != null, Tiger::getTigerSalary, minSalary);

1.7条件优先级控制
1.7.1举例
通过 and()/or() 或 nested() 控制条件分组,避免条件优先级错误:
wrapper.nested(w -> w.gt(Tiger::getTigerAge, 3).gt(Tiger::getTigerSalary, 500))
.or()
.eq(Tiger::getTigerName, "王虎");
1.7.2生成的SQL
(tiger_age > 3 AND tiger_salary > 500) OR tiger_name = '王虎'
1.7.3nested内部类 - 简写Lambda的nested


1.8逻辑删除和物理删除
1.8.1区分逻辑删除和物理删除
逻辑删除是 MyBatis-Plus 提供的 “假删除” 能力:不物理删除数据库记录,仅修改指定字段的状态标记(如deleted=1),保留数据便于恢复和分析,区别于直接删除数据的 “物理删除”。
-
物理删除:真实删除,将 t_tiger 表中对应记录从数据库中移除,后续无法查询;
-
逻辑删除:假删除,将 t_tiger 表中代表 “是否删除” 的字段改为 “已删除状态”,记录仍保存在数据库中,查询时自动过滤已删除数据。(MyBatis Plus 的「逻辑删除」核心就是只标记、不物理删除—— 数据库里的记录永远不会被真正删除,只是通过一个 “删除标记字段”
(比如deleted)标记为 “已删除”,且 MP 会自动帮你处理 CRUD 时的条件过滤,即使是CRUD也是不会在数据库中删除这个记录)
增加delete字段

1.8.2@TableLogic标签(@TableLogic 是 MyBatis Plus 专门用于标记逻辑删除字段的注解,它是实现 “只标记、不物理删除” 的核心注解)

@TableLogic 的核心是:告诉 MyBatis Plus “这个字段是逻辑删除标记字段”,让 MP 自动完成两件事:
-
删除操作:调用
deleteById/remove时,自动把DELETE语句转为UPDATE语句(更新标记字段);

2.查询 / 更新操作:自动给 SQL 拼接 WHERE 逻辑删除字段=未删除值,过滤已标记删除的记录。
1.8.3配置全局逻辑删除规则,适配 t_tiger 表及其他表的逻辑删除字段
#配置全局逻辑删除规则,适配 t_tiger 表及其他表的逻辑删除字段
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 逻辑删除字段的实体类属性名(此处为deleted)
logic-delete-value: 1 # 逻辑已删除值(默认为1,对应t_tiger表的deleted=1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为0,对应t_tiger表的deleted=0)
1.8.4对应关系

entities中的类的删除字段按java命名风格,配置文件,数据库字段的名字按照数据库的下划线命名。
1.8.5案例展示(逻辑上删除了,但是数据库中的记录还在)

二.标签
2.1@TableName :指定数据库表名

2.2@TableId(value="",type=IdType.AUTO ) : 指定主键字段和类型
2.2.1语法格式
专用于标记实体类中的主键属性,绑定数据库表的主键字段,同时指定主键的生成策略(如自增、UUID 等)。

2.2.2value字段:声明主键对应的数据库字段名
| 属性名 | 类型 | 必选 | 说明 |
|---|---|---|---|
| value | String | 否 | 声明主键对应的数据库字段名(默认值:属性名转下划线,如tigerId→tiger_id) |
2.2.3type字段:主键生成策略
| 属性名 | 类型 | 必选 | 说明 |
|---|---|---|---|
| type | IdType | 否 | 主键生成策略(默认值:跟随全局配置,常用AUTO/ASSIGN_ID/INPUT) |
| 策略值 | 含义 | 适用场景 |
|---|---|---|
| AUTO | 数据库自增(依赖表的主键自增配置) | 如 t_tiger 表的 tiger_id(INT AUTO_INCREMENT) |
| ASSIGN_ID | MP 自动生成雪花算法 ID(Long 类型) | 分布式系统、无需数据库自增的主键 |
| ASSIGN_UUID | MP 自动生成 UUID(String 类型,无中划线) | 字符串类型主键、需全局唯一 |
| INPUT |
* /**
* 登录表现层:加@RestController(已保留),通过@Autowired注入Service(移除手动new)
* 仅处理请求、参数校验、调用Service、操作Session、返回响应
*/
@RestController
@RequestMapping("auth")
public class LoginController {
// 核心改造:移除手动new,通过@Autowired从容器注入UserService
@Autowired
private UserService userService;
/**
* 登录接口
* /auth/login post方式 请求体传递参数 username password
* 验证成功以后,将账号存储在session!
* 返回 {code:200,message:"登录成功",data:null}
*/
@PostMapping("login")
public Result login(HttpSession session, @Valid @RequestBody SysUserLoginDto user, BindingResult bindingResult) {
// 1. 表现层职责:仅做参数格式校验(无业务逻辑)
if (bindingResult.hasErrors()) {
return Result.fail(500, "账号和密码不符合规则,登录失败!");
}
// 2. 调用Service完成登录业务校验(不直接调用工具类/DAO)
boolean logined = userService.login(user.getUsername(), user.getPassword());
if (!logined) {
return Result.fail("账号或者密码错误!");
}
// 3. 表现层职责:操作Session(属于请求响应层面,无需走Service)
session.setAttribute("username", user.getUsername());
return Result.success("登录成功!");
}
/**
* 退出登录接口
* /auth/logout get方式 没有参数
* 清空session数据,返回成功响应
* 返回 {code:200,message:"退出登录成功",data:null}
*/
@GetMapping("logout")
public Result logout(HttpSession session) {
// 表现层职责:操作Session(无需走Service/DAO)
session.removeAttribute("username");
session.invalidate();
return Result.success("退出登录成功!");
}
} |
主键非自增、需业务自定义赋值 |
| NONE | 无策略(跟随全局配置) | 沿用项目全局主键策略 |



2.2.4全局配置主键自增
# 全局配置主键自增
mybatis-plus.global-config.db-config.id-type=auto
2.2.5配置文件统一指定表的名称前缀
mybatis-plus.global-config.db-config.table-prefix=t_
2.3@TableField : 匹配表的字段
2.3.1语法格式
专用于标记实体类中的非主键属性,绑定数据库表的普通字段,解决 “属性名与字段名不一致、字段是否参与 CRUD” 等问题。

2.3.2字段汇总
| 属性名 | 类型 | 必选 | 说明 |
|---|---|---|---|
| value | String | 否 | 声明属性对应的数据库字段名(默认值:属性名转下划线,如tigerName→tiger_name)【绑定这种普通的匹配,比如:t_id 匹配 tID的时候,value可以省略】 |
| exist | boolean | 否 | 标记属性是否对应数据库字段(true:存在;false:仅实体类属性,无对应字段) |
| fill | FieldFill | 否 | 字段自动填充策略(如创建时间、修改时间自动赋值) |
| select | boolean | 否 | 标记字段是否参与查询(true:参与;false:查询时忽略该字段) |

2.4@Configuration+@Bean标签声明Bean对象
2.4.1怎么理解POJO生命周期和Bean生命周期的区别(我的理解)
我可以理解为,类似于工具,需要被从Spring项目启动到结束,被很多服务调用的,如果是组件,就加@Component以及子标签的组件标签,如果是别的第三方的工具等(比如 Redis、线程池),就加@Configuration和@Bean
2.4.2使用@Configuration+@Bean生命和管理Druid数据库
@Configuration
@PropertySource("classpath:config/jdbc.properties")
public class Demo15Config {
// 省略配置参数注入的属性...
/**
* 创建Druid数据源Bean,纳入IoC容器管理
* @Bean("myDruidDataSource"):自定义Bean的ID为myDruidDataSource(默认是方法名getDruidDataSource)
* @Scope("prototype"):设置为多实例(默认单例,开发中极少用多实例)
* @return DruidDataSource对象(IoC容器会缓存该对象)
*/
@Bean("myDruidDataSource")
// @Scope("prototype") // 如需多实例则打开注释,默认单例无需配置
public DataSource getDruidDataSource() {
// 手动创建Druid数据源对象(第三方类,无法加@Component注解)
DruidDataSource druidDataSource = new DruidDataSource();
// 设置数据库连接参数(从配置文件注入的属性)
druidDataSource.setUsername(userName);
druidDataSource.setPassword(password);
druidDataSource.setUrl(url);
druidDataSource.setDriverClassName(driverClassName);
// 返回对象:Spring会自动将该对象存入IoC容器
return druidDataSource;
}
}
2.5IPage分页

2.5.1声明MybatisPlusInterceptor拦截器作为Bean(可复用-注意更改DbType.为自己数据库产品名)
@Configuration
public class MPConfiguration {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 核心:添加分页插件,指定数据库类型为MySQL(适配t_tiger表)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
更多推荐



所有评论(0)