MyBatis-Plus 入门详解:从简介到 CRUD 实战
一、MyBatis-Plus 简介
1.1 什么是 MyBatis-Plus?
MyBatis-Plus(简称 MP)是 MyBatis 的增强工具,它在 MyBatis 的基础上只做增强、不做改变,核心目标是简化开发流程、提高开发效率。通过提供通用的 Mapper 和 Service,MP 可以让开发者在不编写任何 SQL 语句的前提下,快速实现单表的增删改查(CRUD)、批量操作、逻辑删除、分页等功能,是 MyBatis 的 “最佳搭档”。
1.2 核心特性
MyBatis-Plus 的特性可以用 “强大且贴心” 来概括,主要包括:
- 无侵入性:引入后不会影响现有工程,使用方式与 MyBatis 无缝衔接;
- 损耗小:启动时自动注入基本 CRUD 操作,性能几乎无损耗,直接面向对象编程;
- 强大的 CRUD 操作:内置通用 Mapper 和 Service,少量配置即可实现单表大部分操作,配合条件构造器满足复杂查询需求;
- Lambda 表达式支持:通过 Lambda 编写查询条件,避免字段名拼写错误;
- 主键自动生成:支持 4 种主键策略(含分布式唯一 ID 生成器 Sequence),解决主键生成难题;
- ActiveRecord 模式:实体类继承 Model 类即可直接进行 CRUD 操作,简化代码;
- 全局通用操作:支持全局通用方法注入,实现 “一次编写,多处使用”;
- 内置工具:包括代码生成器(快速生成各层代码)、分页插件(支持多数据库)、性能分析插件(输出 SQL 及执行时间)、全局拦截插件(防止误操作)等。
1.3 支持的数据库
任何支持 MyBatis 且兼容标准 SQL 的数据库都可以使用 MyBatis-Plus,包括但不限于 MySQL、MariaDB、Oracle、DB2、H2、SQLite、PostgreSQL、SQLServer 等。
1.4 官方资源
- 官方地址:http://mp.baomidou.com
- 代码仓库:
- Github:https://github.com/baomidou/mybatis-plus
- Gitee:https://gitee.com/baomidou/mybatis-plus
- 文档地址:https://baomidou.com/pages/24112f
二、MyBatis-Plus 入门案例
2.1 开发环境准备
- IDE:IntelliJ IDEA 2017+
- JDK:JDK 1.8
- 构建工具:Maven 3.6.0+
- MySQL:5.6(或 5.7、8.0)
- Spring Boot:2.7.4
- MyBatis-Plus:3.5.1
2.2 数据库与表设计
首先创建数据库和表,用于后续案例演示。
- 创建数据库:
CREATE DATABASE `mybatis_plus` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;USE `mybatis_plus`;
- 创建用户表:
CREATE TABLE `user` ( `id` bigint(20) NOT NULL COMMENT \'主键ID\', `name` varchar(30) DEFAULT NULL COMMENT \'姓名\', `age` int(11) DEFAULT NULL COMMENT \'年龄\', `email` varchar(50) DEFAULT NULL COMMENT \'邮箱\', PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- 插入测试数据:
INSERT INTO user (id, name, age, email) VALUES(1, \'Jone\', 18, \'test1@baomidou.com\'),(2, \'Jack\', 20, \'test2@baomidou.com\'),(3, \'Tom\', 28, \'test3@baomidou.com\'),(4, \'Sandy\', 21, \'test4@baomidou.com\'),(5, \'Billie\', 24, \'test5@baomidou.com\');
2.3 创建 Spring Boot 工程
2.3.1 初始化工程
使用 Spring Initializr(https://start.spring.io/)快速创建一个 Spring Boot 工程,选择必要的基础依赖(如 Spring Web)。
2.3.2 引入核心依赖
在pom.xml
中添加 MyBatis-Plus、Lombok、MySQL 驱动依赖:
com.baomidou mybatis-plus-boot-starter 3.5.1 org.projectlombok lombok true mysql mysql-connector-java runtime
2.3.3 安装 Lombok 插件
IDEA 中需安装 Lombok 插件(File -> Settings -> Plugins
,搜索 Lombok 并安装),否则会提示注解相关错误。要重启
2.4 编写核心代码
2.4.1 配置数据源(application.yml)
配置数据库连接信息,注意 MySQL 版本差异:
spring: datasource: type: com.zaxxer.hikari.HikariDataSource # Spring Boot 2.x默认连接池 driver-class-name: com.mysql.cj.jdbc.Driver # MySQL 8.0+推荐使用此驱动(5.x可用com.mysql.jdbc.Driver) url: jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8 # MySQL 8.0需指定时区 username: root password: 你的数据库密码# 配置MyBatis日志(可选,用于查看SQL执行过程)mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
1、驱动类driver-class-name
spring boot 2.0(内置jdbc5驱动),驱动类使用
driver-class-name: com.mysql.jdbc.Driver
spring boot 2.1及以上(内置jdbc8驱动),驱动类使用:
driver-class-name: com.mysql.cj.jdbc.Driver
否则运行测试用例的时候会有 WARN 信息
2、连接地址url
MySQL5.7版本的url:
jdbc:mysql://localhost:3306/mybatis_plus?characterEncoding=utf-8&useSSL=false
MySQL8.0版本的url:
jdbc:mysql://localhost:3306/mybatis_plus?
serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false
否则运行测试用例报告如下错误:
java.sql.SQLException: The server time zone value\'Öйú±ê׼ʱ¼ä\' is unrecognized or represents more
mysql 5和8 的驱动类取决与springboot是否是2.1之前的版本。
要是8 就是com.mysql.cj.jdbc.Driver
要是5 就是com.mysql.jdbc.Driver
和本地的版本无关
其次,
url是和本地的mysql版本有关。8以上就要加时区
2.4.2 启动类(添加 Mapper 扫描)
在启动类上添加@MapperScan
注解,指定 Mapper 接口所在的包路径:
import org.mybatis.spring.annotation.MapperScan;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication@MapperScan(\"com.example.mybatisplus.mapper\") // 扫描Mapper接口包public class MybatisPlusApplication { public static void main(String[] args) { SpringApplication.run(MybatisPlusApplication.class, args); }}
2.4.3 实体类(User.java)
使用 Lombok 注解简化 getter、setter、构造器等代码:
import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data // 自动生成getter、setter、toString等@AllArgsConstructor // 全参构造器@NoArgsConstructor // 无参构造器public class User { private Long id; private String name; private Integer age; private String email;}
2.4.4 Mapper 接口(UserMapper.java)
继承 MyBatis-Plus 提供的BaseMapper
,无需编写方法即可获得 CRUD 能力:
import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.example.mybatisplus.entity.User;import org.springframework.stereotype.Repository;@Repository // 标记为Spring数据访问层组件,避免IDE报错public interface UserMapper extends BaseMapper { // 无需编写方法,BaseMapper已提供所有基础CRUD操作}
2.5 测试 CRUD 操作
通过 Spring Boot 测试类验证 MyBatis-Plus 的 CRUD 功能,注入UserMapper
后直接调用方法即可。
package com.qcby.springbootmybitasplus;import com.baomidou.mybatisplus.test.autoconfigure.MybatisPlusTest;import com.qcby.springbootmybitasplus.entity.User;import com.qcby.springbootmybitasplus.mapper.UserMapper;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;@SpringBootTest//@MybatisPlusTestclass SpringbootMybitasPlusApplicationTests { @Autowired private UserMapper userMapper; @Test public void testSelectList(){//selectList()根据MP内置的条件构造器查询一个list集合,null表示没有条件,即查询所有 userMapper.selectList(null).forEach(System.out::println); }}
Bean对象,但是可以正常读取数据正常运行在测试mybatis plus 的mapper时,自己的mapper接口不加@Repository注解为什么会提示找不到具体
IDEA在 userMapper 处报错,因为找不到注入的对象,因为类是动态创建的,但是程序可以正确 的执行。
为了避免报错,可以在mapper接口上添加 @Repository 注解
添加日志
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
BaseMapper
MyBatis-Plus中的基本CRUD在内置的BaseMapper中都已得到了实现,我们可以直接使用,接口如下:
package com.baomidou.mybatisplus.core.mapper; public interface BaseMapper extends Mapper { /** * 插入一条记录 * @param entity 实体对象 */ int insert(T entity); /** * 根据 ID 删除 * @param id 主键ID */ int deleteById(Serializable id); /** * 根据实体(ID)删除 * @param entity 实体对象 * @since 3.4.4 */ int deleteById(T entity); /** * 根据 columnMap 条件,删除记录 * @param columnMap 表字段 map 对象 */ int deleteByMap(@Param(Constants.COLUMN_MAP) Map columnMap); /** * 根据 entity 条件,删除记录 * @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) */ int delete(@Param(Constants.WRAPPER) Wrapper queryWrapper); /** * 删除(根据ID 批量删除) * @param idList 主键ID列表(不能为 null 以及 empty) */ int deleteBatchIds(@Param(Constants.COLLECTION) Collection idList); /** * 根据 ID 修改 * @param entity 实体对象 */ int updateById(@Param(Constants.ENTITY) T entity); /** * 根据 whereEntity 条件,更新记录 * @param entity 实体对象 (set 条件值 ,可以为 null) * @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句) */ int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper updateWrapper); /** * 根据 ID 查询 * @param id 主键ID */ T selectById(Serializable id); /** * 查询(根据ID 批量查询) * @param idList 主键ID列表(不能为 null 以及 empty) */ List selectBatchIds(@Param(Constants.COLLECTION) Collection idList); /** * 查询(根据 columnMap 条件) * @param columnMap 表字段 map 对象 */ List selectByMap(@Param(Constants.COLUMN_MAP) Map columnMap); /** * 根据 entity 条件,查询一条记录 * 查询一条记录,例如 qw.last(\"limit 1\") 限制取一条记录 , 注意:多条数据会报异常
* @param queryWrapper 实体对象封装操作类(可以为 null) */ default T selectOne(@Param(Constants.WRAPPER) Wrapper queryWrapper) { List ts = this.selectList(queryWrapper); if (CollectionUtils.isNotEmpty(ts)) { if (ts.size() != 1) { throw ExceptionUtils.mpe(\"One record is expected, but the query result is multiple records\"); } return ts.get(0); } return null; } /** * 根据 Wrapper 条件,查询总记录数 * @param queryWrapper 实体对象封装操作类(可以为 null) */ Long selectCount(@Param(Constants.WRAPPER) Wrapper queryWrapper); /** * 根据 entity 条件,查询全部记录 * @param queryWrapper 实体对象封装操作类(可以为 null) */ List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper); /** * 根据 Wrapper 条件,查询全部记录 * @param queryWrapper 实体对象封装操作类(可以为 null) */ List<Map> selectMaps(@Param(Constants.WRAPPER) Wrapper queryWrapper); /** * 根据 Wrapper 条件,查询全部记录 * 注意: 只返回第一个字段的值
* @param queryWrapper 实体对象封装操作类(可以为 null) */ List selectObjs(@Param(Constants.WRAPPER) Wrapper queryWrapper); /** * 根据 entity 条件,查询全部记录(并翻页) * @param page 分页查询条件(可以为 RowBounds.DEFAULT) * @param queryWrapper 实体对象封装操作类(可以为 null) */ <P extends IPage> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper queryWrapper); /** * 根据 Wrapper 条件,查询全部记录(并翻页) * @param page 分页查询条件 * @param queryWrapper 实体对象封装操作类 */ <P extends IPage<Map>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper queryWrapper);}
基本CRUD
1. 插入一条记录
/*** 插入一条记录* @param entity 实体对象 */int insert(T entity);
测试代码
@Testpublic void testInsert(){ User user = new User(null, \"张三\", 23, \"zhangsan@qcby.com\"); // 执行的SQL:INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? ) int result = userMapper.insert(user); System.out.println(\"受影响行数:\"+result); // 输出示例:1475754982694199298 System.out.println(\"id自动获取:\"+user.getId());}
说明
执行后会自动生成 ID(示例结果:1903360524240498689),这是因为 MyBatis-Plus 默认使用雪花算法生成主键 ID,可保证分布式环境下的 ID 唯一性。
2. 删除操作
2.1 根据 ID 删除
原码
/*** 根据 ID 删除* @param id 主键ID */int deleteById(Serializable id);
测试代码
@Testpublic void testDeleteById(){ // 通过id删除用户信息,执行的SQL:DELETE FROM user WHERE id=? int result = userMapper.deleteById(1903360524240498689L); System.out.println(\"受影响行数:\"+result);}
2.2 根据实体(ID)删除
原码
/*** 根据实体(ID)删除* @param entity 实体对象* @since 3.4.4 */int deleteById(T entity);
测试代码
/** * 根据用户ID删除(通过实体对象传递ID) */@Testpublic void deleteByUserID(){ int result = userMapper.deleteById(8L); // 此处直接传入ID(本质与2.1一致,也可传入含ID的实体对象) System.out.println(\"受影响的行数:\"+result);}
2.3 根据 columnMap 条件删除
原码
/*** 根据 columnMap 条件,删除记录* @param columnMap 表字段 map 对象 */int deleteByMap(@Param(Constants.COLUMN_MAP) Map columnMap);
测试代码
@Testpublic void testDeleteByMap(){ // 根据map集合中设置的条件删除记录,执行的SQL:DELETE FROM user WHERE name = ? AND age = ? Map map = new HashMap(); map.put(\"age\", 23); // 条件1:age=23 map.put(\"name\", \"张三\"); // 条件2:name=张三 int result = userMapper.deleteByMap(map); System.out.println(\"受影响行数:\"+result);}
2.4 根据 entity 条件删除
原码
/*** 根据 entity 条件,删除记录* @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/int delete(@Param(Constants.WRAPPER) Wrapper queryWrapper);
测试代码
/** * 根据entity条件删除记录 */@Testpublic void deleteByEntity(){ User user = new User(); user.setName(\"nn\"); // 条件1:name=nn user.setAge(22); // 条件2:age=22 // 用QueryWrapper封装条件(基于实体对象) QueryWrapper queryWrapper = new QueryWrapper(user); int result = userMapper.delete(queryWrapper); System.out.println(\"受影响的行数:\"+result);}
2.5 根据 ID 批量删除
原码
/*** 删除(根据ID 批量删除)* @param idList 主键ID列表(不能为 null 以及 empty) */int deleteBatchIds(@Param(Constants.COLLECTION) Collection idList);
测试代码
@Testpublic void testDeleteBatchIds(){ // 通过多个id批量删除,执行的SQL:DELETE FROM user WHERE id IN ( ? , ? , ? ) List idList = Arrays.asList(1L, 2L, 3L); // 要删除的ID列表 int result = userMapper.deleteBatchIds(idList); System.out.println(\"受影响行数:\"+result);}
3. 修改操作
3.1 根据 ID 修改
原码
/*** 根据 ID 修改* @param entity 实体对象 */int updateById(@Param(Constants.ENTITY) T entity);
测试代码
@Testpublic void testUpdateById(){ User user = new User(4L, \"admin\", 22, null); // 仅修改非null字段(id为条件,name和age为修改值) // 执行的SQL:UPDATE user SET name=?, age=? WHERE id=? int result = userMapper.updateById(user); System.out.println(\"受影响行数:\"+result);}
3.2 根据 whereEntity 条件更改
原码
/*** 根据 whereEntity 条件,更新记录* @param entity 实体对象 (set 条件值,可以为 null)* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)*/int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper updateWrapper);
测试代码
/** * 根据whereEntity条件更新 */@Testpublic void testUpdateByWhere(){ User updateUser = new User(); updateUser.setName(\"Updated\"); // 要修改的字段1:name=Updated updateUser.setAge(30); // 要修改的字段2:age=30 User oldUser = new User(); oldUser.setName(\"丽丽\"); // 条件1:name=丽丽 oldUser.setAge(33); // 条件2:age=33 // 用UpdateWrapper封装更新条件(基于oldUser) UpdateWrapper updateWrapper = new UpdateWrapper(oldUser); int result = userMapper.update(updateUser, updateWrapper); System.out.println(\"受影响行数:\"+result);}
4. 查询操作
4.1 根据 ID 查询
原码
/*** 根据 ID 查询* @param id 主键ID */T selectById(Serializable id);
测试代码
@Testpublic void testSelectById(){ // 根据id查询用户信息,执行的SQL:SELECT id,name,age,email FROM user WHERE id=? User user = userMapper.selectById(4L); System.out.println(user);}
4.2 根据 ID 批量查询
原码
/*** 查询(根据ID 批量查询)* @param idList 主键ID列表(不能为 null 以及 empty) */List selectBatchIds(@Param(Constants.COLLECTION) Collection idList);
测试代码
@Testpublic void testSelectBatchIds(){ // 根据多个id查询多个用户信息,执行的SQL:SELECT id,name,age,email FROM user WHERE id IN ( ? , ? ) List idList = Arrays.asList(4L, 5L); // 要查询的ID列表 List list = userMapper.selectBatchIds(idList); list.forEach(System.out::println); // 用Lambda表达式遍历输出}
4.3 根据 columnMap 条件查询
原码
/*** 查询(根据 columnMap 条件)* @param columnMap 表字段 map 对象 */List selectByMap(@Param(Constants.COLUMN_MAP) Map columnMap);
测试代码
@Testpublic void testSelectByMap(){ // 通过map条件查询用户信息,执行的SQL:SELECT id,name,age,email FROM user WHERE name = ? AND age = ? Map map = new HashMap(); map.put(\"age\", 22); // 条件1:age=22 map.put(\"name\", \"admin\"); // 条件2:name=admin List list = userMapper.selectByMap(map); list.forEach(System.out::println);}
4.4 根据 entity 条件查询一条记录
原码
/*** 根据 entity 条件,查询一条记录* 查询一条记录,例如 qw.last(\"limit 1\") 限制取一条记录,注意:多条数据会报异常
* @param queryWrapper 实体对象封装操作类(可以为 null)*/default T selectOne(@Param(Constants.WRAPPER) Wrapper queryWrapper) { List ts = this.selectList(queryWrapper); if (CollectionUtils.isNotEmpty(ts)) { if (ts.size() != 1) { throw ExceptionUtils.mpe(\"One record is expected, but the query result is multiple records\"); } return ts.get(0); } return null;}
测试代码
-
多条记录时(会报错):
@Testpublic void testSelectByEntity(){ User user = new User(); user.setAge(22); // 假设满足age=22的记录有2条 QueryWrapper queryWrapper = new QueryWrapper(user); System.out.println(userMapper.selectOne(queryWrapper)); // 抛出异常:期望1条记录,但查询到多条}
-
单条记录时(正常返回):
@Testpublic void testSelectByEntity(){ User user = new User(); user.setAge(30); user.setName(\"Updated\"); // 假设满足age=30且name=Updated的记录只有1条 QueryWrapper queryWrapper = new QueryWrapper(user); System.out.println(userMapper.selectOne(queryWrapper)); // 正常返回该记录}
4.5 根据 wrapper 条件查询总记录数
原码
/*** 根据 Wrapper 条件,查询总记录数* @param queryWrapper 实体对象封装操作类(可以为 null) */Long selectCount(@Param(Constants.WRAPPER) Wrapper queryWrapper);
测试代码
/** * 根据Wrapper条件查询总记录数 */@Testpublic void testByWrapper(){ User user = new User(); user.setAge(22); // 条件:age=22 QueryWrapper queryWrapper = new QueryWrapper(user); System.out.println(userMapper.selectCount(queryWrapper)); // 输出满足条件的记录总数}
4.6 根据 entity 条件查询全部记录
原码
/*** 根据 entity 条件,查询全部记录* @param queryWrapper 实体对象封装操作类(可以为 null) */List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper);
测试代码
@Testpublic void testSelectList1(){ // 查询所有用户信息,执行的SQL:SELECT id,name,age,email FROM user List list = userMapper.selectList(null); // null表示无查询条件(查询全部) list.forEach(System.out::println);}
4.7 根据 wrapper 条件查询全部记录(封装为 Map)
原码
/*** 根据 Wrapper 条件,查询全部记录* @param queryWrapper 实体对象封装操作类(可以为 null) */List<Map> selectMaps(@Param(Constants.WRAPPER) Wrapper queryWrapper);
测试代码
/** * 根据wrapper条件查询全部记录(结果封装为Map) */@Testpublic void testDelectMaps(){ List<Map> resultList = userMapper.selectMaps(null); // 查询全部,结果为Map列表 // 输出查询结果(Map的key为表字段名,value为字段值) for (Map result : resultList) { System.out.println(result); }}
4.8 根据 wrapper 条件查询全部记录(返回第一个字段值)
原码
/*** 根据 Wrapper 条件,查询全部记录* 注意: 只返回第一个字段的值
* @param queryWrapper 实体对象封装操作类(可以为 null) */List selectObjs(@Param(Constants.WRAPPER) Wrapper queryWrapper);
测试代码
/** * 根据wrapper条件查询全部记录,只返回第一个字段的值 */@Testpublic void testSelectObjs(){ List resultObjs = userMapper.selectObjs(null); // 查询全部,只返回每条记录的第一个字段(此处为id) for(Object o : resultObjs){ System.out.println(o); // 输出所有id }}
4.9 根据 entity 条件查询全部记录并翻页
原码
/*** 根据 entity 条件,查询全部记录(并翻页)* @param page 分页查询条件(可以为 RowBounds.DEFAULT)* @param queryWrapper 实体对象封装操作类(可以为 null) */<P extends IPage> P selectPage(P page, @Param(Constants.WRAPPER) Wrapper queryWrapper);
测试代码
/** * 根据entity条件查询并翻页 */@Testpublic void testSelectPage(){ Page p = new Page(1, 5); // 第1页,每页5条记录 IPage results = userMapper.selectPage(p, null); // 无查询条件,查询全部并分页 // 输出分页信息 System.out.println(\"当前页: \" + results.getCurrent()); System.out.println(\"每页记录数: \" + results.getSize()); System.out.println(\"总记录数: \" + results.getTotal()); System.out.println(\"总页数: \" + results.getPages()); // 输出当前页的记录(getRecords()获取分页数据列表) results.getRecords().forEach(user -> System.out.println(user));}
4.10 根据 wrapper 条件查询全部记录并翻页(封装为 Map)
原码
/*** 根据 Wrapper 条件,查询全部记录(并翻页)* @param page 分页查询条件* @param queryWrapper 实体对象封装操作类 */<P extends IPage<Map>> P selectMapsPage(P page, @Param(Constants.WRAPPER) Wrapper queryWrapper);
测试代码
/** * 根据wrapper条件查询并翻页(结果封装为Map) */@Testpublic void testSelectMapsPage(){ Page<Map> page = new Page(); // 默认第1页,每页10条 IPage<Map> results = userMapper.selectMapsPage(page, null); // 无查询条件,分页查询全部 // 输出分页信息 System.out.println(\"当前页: \" + results.getCurrent()); System.out.println(\"每页记录数: \" + results.getSize()); System.out.println(\"总记录数: \" + results.getTotal()); System.out.println(\"总页数: \" + results.getPages()); // 输出当前页的记录(Map格式) results.getRecords().forEach(record -> System.out.println(record));}
三、核心概念补充
3.1 BaseMapper 详解
BaseMapper
是 MP 的核心接口,封装了 17 个常用 CRUD 方法,泛型T
为实体类类型。主要方法包括:
insert(T entity)
:插入deleteById(Serializable id)
:按 ID 删除updateById(T entity)
:按 ID 更新selectById(Serializable id)
:按 ID 查询selectList(Wrapper wrapper)
:条件查询列表selectPage(IPage page, Wrapper wrapper)
:分页查询
3.2 @MapperScan 与 @Repository 的区别
@MapperScan
:MyBatis-Plus 注解,用于扫描指定包下的 Mapper 接口,自动生成代理实现类并注册为 Spring Bean;@Repository
:Spring 注解,标记接口为数据访问层组件,仅用于消除 IDE 的 “未注入” 警告,不影响功能。
四、MapperScan和repository的区别
接口的代理实现类是由框架来提供的,所以我们需要配置一个单独扫描mapper的扫描器。
@MapperScan是 MyBatis-Spring 框架里的注解。MyBatis 是一个优秀的持久层框架,而 MyBatis-Spring 则让 MyBatis 能更好地集成到 Spring 框架中。
作用:它的作用是扫描指定包下的所有接口,并把这些接口自动注册为 MyBatis 的 Mapper Bean。这样一来,我们就无需在每个 Mapper 接口上单独添加@Mapper注解了。
@Repository是 Spring 框架自带的注解。
将类(这个接口的代理类)交给Spring去管理,而这个代理类是由mybatisPlus(MyBatis的增强,还是MyBatis)实现的。管理着它的实现类,要是没有这个注解,就需要userMapperImpl,但是mybatisPlus框架都给提供了。
如果不加,他会报波浪线,但是不出错。
如果这个接口有很多实现类,加了@Repository注解,就明确告诉它,用的是框架提供的实现类。