MyBatis-Plus 从入门到实战目录
前言
- 重要的事情先开头说,这篇博客篇幅很长,我相信你耐心看完这一篇 MyBatis-Plus 之后,绝对能将它应用到实战当中,因为这篇是结合SpringBoot(快速搭建开发环境),MySQL一套讲的。
- 在说 MyBatis-Plus 之前,我们先回顾一下 MyBatis,MyBatis 是一个简化 JDBC 操作数据库的 ORM 框架,MyBatis 最大的特点就是省去了原生的 JDBC 操作数据库的繁琐过程,但是唯独 SQL 语句让我们自己编写,因为框架一般都是简化某某某操作,却很少能优化某某某操作。我们可以根据特定的业务编写出最优的 SQL 语句,最大力度的提高数据库查询效率,这也是 MyBatis 和 JPA(JPA是一套操作数据库的接口规范,它最让人熟悉的实现框架就是Hibernate)最大的区别之处,JPA 不管是单表还是多表操作,都不用写 SQL,这样在复杂的查询情况下效率就会很低下。
- 好了,说完了 MyBatis,现在开始说 MyBatis-Plus,Plus 就是增强的意思,增强什么呢?上面说了 MyBatis 最大的特点就是在省去大量繁琐的相同操作过程之外,还可以让我们可以自定义 SQL 语句。如果不是需要优化的 SQL,我相信大多数人都不想写SQL,看来 MyBatis 还是不太懂我们的心思(偷懒是每个人都想做的事情),这是号称 MyBatis 的孪生兄弟 MyBatis-Plus 就出来了,
MyBatis-Plus 的宗旨是为了简化开发而生(简化 MyBatis 操作)。 - 下面摘自 MyBatis-Plus官网阐述 MyBatis-Plus 的特性,下图也是来源于其官网。
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
- 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求。
- 支持主键自动生成:支持多达 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

MyBatis-Plus 架构
简单谈谈 MyBatis-Plus 底层实现原理
- 我们使用了 MyBatis-Plus 的时候,需要在 SpringBoot 的启动类上面添加
@MapperScan注解来扫描 Mapper 接口,这样就能通过反射+动态代理生成 Mapper 接口的实现类了。 - 然后我们会创建一些与数据库表对应的实体类,这时 MyBatis-Plus 会通过反射机制自动扫描实体类的内部结构,然后基于抽取出来的属性信息来映射成表字段,然后再生成对应的单表增删改查 SQL 语句,最后将这些 SQL 语句注入到 MyBatis 容器当中。
- 通过上面的简单概述,我们可以知道 MyBatis-Plus 为我们简化了单表的增删改查,因为 MyBatis-Plus 生成单表的增删改查和我们自己写的效率是差不多的,这对于我们开发来说方便了许多。

MyBatis-Plus 快速入门(结合 SpringBoot )
- 使用 Spring 脚手架创建 SpringBoot 项目,如果不太熟悉 IDEA 快速生成 SpringBoot 项目,可以先看下面一篇博客,几分钟就搞定。
SpringBoot 快速入门 - 导入相关依赖
下面的依赖应该是一个基本的 SpringBoot 项目必备的,每个依赖都添加注释说明<dependencies> <!-- MyBatis-Plus 依赖 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.2.0</version> </dependency> <!-- MySql 驱动包 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!-- Lombok 依赖 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <!-- Web 开发依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- SpringBoot 测试环境依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> - 数据库表以及插值语句
简单说一下表字段作用(选说)- create_time,update_time为了之后讲解 MyBatis-Plus 的
自动填充而创建的 - deleted为了之后讲解 MyBatis-Plus 的
逻辑删除而创建的 - 其他的字段都是普通的信息字段
CREATE TABLE `user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `name` varchar(30) DEFAULT NULL COMMENT '姓名', `age` int(11) DEFAULT NULL COMMENT '年龄', `email` varchar(50) DEFAULT NULL COMMENT '邮箱', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `update_time` datetime DEFAULT NULL COMMENT '更新时间', `deleted` int(1) DEFAULT NULL COMMENT '逻辑删除', `sex` int(1) DEFAULT '1' COMMENT '1-男,0-女', PRIMARY KEY (`id`) ) ENGINE=InnoDB CHARSET=utf8; INSERT INTO `user` VALUES (1, 'zs', 18, 'zs@zs.com', '2020-07-28 21:59:24', '2020-05-13 01:17:01', NULL, 1); INSERT INTO `user` VALUES (2, 'ls', 20, 'ls@ls.com', '2020-07-28 21:59:21', '2020-05-13 01:17:01', NULL, 1); INSERT INTO `user` VALUES (3, 'ww', 19, 'ww@qq.com', '2020-07-28 19:44:38', '2020-05-13 01:17:01', NULL, 1); INSERT INTO `user` VALUES (4, 'zl', 21, 'zl@zl.com', '2020-07-28 21:59:27', '2020-05-13 01:17:01', NULL, 1); INSERT INTO `user` VALUES (5, 'sq', 24, 'sq@sq.com', '2020-07-28 21:59:29', '2020-05-13 01:17:01', NULL, 1); INSERT INTO `user` VALUES (6, 'xe', 21, 'xe@xe.com', '2020-05-12 09:13:35', '2020-05-13 01:26:53', NULL, 1); - create_time,update_time为了之后讲解 MyBatis-Plus 的
- 编写实体类
- 实体类上面的注解都是 Lombok 插件的注解,都是为了简化实体类而诞生的
- 属性上面的注解是 MyBatis-Plus 提供的注解,之后再详细说明每一个注解的作用
@Data @EqualsAndHashCode(callSuper = false) @AllArgsConstructor @NoArgsConstructor @TableName("user") public class User extends Model<User> { @TableId(type=IdType.AUTO) private Long id; private String name; private Integer age; private String email; @TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; @TableLogic private Integer deleted; private SexEnum sex; } - 配置数据源信息
这里简单配置4大数据源参数,数据库连接池采用 SpringBoot 默认的(可以尝试自己替换成阿里的 Druid)spring: datasource: username: root password: root url: jdbc:mysql://localhost:3306/mybatis-plus?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false driver-class-name: com.mysql.jdbc.Driver - 扫描 Mapper 接口,在 SpringBoot 启动类中添加
@MapperScan注解,扫描 Mapper 接口文件夹,下面是我项目中的 Mapper 接口所在的包名,大家换成自己的包名即可。@SpringBootApplication @MapperScan("cn.zwq.mpmybaitsplus.mapper") public class MpMybaitsplusApplication { public static void main(String[] args) { SpringApplication.run(MpMybaitsplusApplication.class, args); } } - 编写 Mapper 接口,下面接口我们继承了 MyBatis-Plus 中的 BaseMapper 接口,该接口内置了单表的增删改查方法,根据 Java 中的继承特点,子接口(我们自己编写的 UserMapper )也就拥有了单表的增删改查方法。
下图就是 BaseMapper 接口内置的方法,增删改查方法都涵盖了,包括条件查询的增删改查方法。public interface UserMapper extends BaseMapper<User> {}
- 在 SpringBoot 测试环境下,测试 SpringBoot 整合 MyBatis-Plus 是否成功
查询全部数据
Wrapper 是 MyBatis-Plus 用来封装查询条件的,如果为null,说明没有查询条件
下图查询结果如下图所示,我们调用了方法,内部自动发送了SQL语句,根据所有字段查询记录,也做了一些SQL优化操作。@RunWith(SpringRunner.class) @SpringBootTest public class MpMybaitsplusApplicationTests { @Autowired private UserMapper userMapper; @Test public void selectList(){ /** * 查询全部记录 * @param queryWrapper 实体对象封装操作类(可以为 null) * List<T> selectList (@Param(Constants.WRAPPER) Wrapper < T > queryWrapper); */ List<User> users = userMapper.selectList(null); users.forEach(System.out::println); } }
如果大家的控制台没有显示 SQL 语句,说明还没配置 MyBatis-Plus 相关日志,可以按照下图开启 MyBatis-Plus 日志。
- 这样我们就完成了 MyBatis-Plus 入门操作了,下面将会再详细介绍 MyBatis-Plus 增删改查操作,不过下面讲解不会再像上面一样截图说明了,比如增删改代码都是直接贴代码讲流程思路,都是经过我验证了(成功更改数据库数据),所以贴出来的一般代码不会有问题,除非你们的环境与我现在开发的环境不同。
BaseMapper 方法详细说明
- 上面也说了,使用 MyBatis-Plus 之后,我们只需要继承 BaseMapper 即可简化单表的增删改查操作。
- BaseMapper 接口方法如下

Insert方法
- 插入一条记录
int insert(T entity);
Delete方法
- 根据 entity 条件,删除记录
int delete(@Param(Constants.WRAPPER) Wrapper wrapper); - 删除(根据ID 批量删除)
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); - 根据 ID 删除
int deleteById(Serializable id); - 根据 columnMap 条件,删除记录
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);
Update方法
- 根据 whereEntity 条件,更新记录
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper updateWrapper); - 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);
Select方法
- 根据 ID 查询
T selectById(Serializable id); - 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper queryWrapper); - 查询(根据ID 批量查询)
List selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList); - 根据 entity 条件,查询全部记录
List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper); - 查询(根据 columnMap 条件)
List selectByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap); - 根据 Wrapper 条件,查询全部记录
List<Map<String, Object>> selectMaps(@Param(Constants.WRAPPER) Wrapper queryWrapper); - 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List selectObjs(@Param(Constants.WRAPPER) Wrapper queryWrapper); - 根据 entity 条件,查询全部记录(并翻页)
IPage selectPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper); - 根据 Wrapper 条件,查询全部记录(并翻页)
IPage<Map<String, Object>> selectMapsPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper); - 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper queryWrapper);
Wrapper条件封装器
- Wrapper 是 MyBatis-Plus 中提供的条件封装器,重点掌握几个 Wrapper 的实现类即可。
下面圈起来的重点掌握即可,不过我常用的是上面两个圈起来的,下面两个是基于 Lambda 表达式的条件封装器。之后再结合案例讲解它们的具体用法。
MyBatis-Plus 下的实体类详细说明
- 实体类对应数据库表
- 属性对应字段
@TableName
- 当实体类类名与数据库表名称不一样的时候,就需要使用这个注解

@TableId
- 标识这个属性为数据库表主键,MyBatis-Plus提供很多种数据库主键生成策略,都定义在这个枚举类
IdType当中。
@TableField
对象属性名与字段名不一致问题(非驼峰)
对象属性不存在表字段对应
属性 类型 必须指定 默认值 描述 value String 否 “” 字段名,如果属性名和字段名一样,就不需要指定 el string 否 exist boolean 否 true 是否为数据库表字段,不是需要指定为false fill Enum 否 FieldFill.DEFAULT 字段自动填充策略,比如在插入或者更新数据的时候, 可以使用自动填充策略,这样就不需要显示赋值了。 select boolean 否 true 是否进行select查询。为false在查询时就不会查询该字段
详细讲解 MyBatis-Plus 增删改查操作
- 接下来使用代码讲解 MyBatis-Plus 增删改查方法,结合代码与流程思路说明,可能不截图展示结果了。
insert方法
- 插入对象需要我们创建一个 User 对象,然后为对象属性赋值,最后调用 MyBatis-Plus 插入方法即可。

@Test public void insertUser(){ User user = new User(); user.setAge(22); user.setName("xq"); user.setEmail("xq@qq.com"); userMapper.insert(user); System.out.println(user); }
主键生成策略
- 上面方法执行之后,成功往数据库插入一条数据,我们都知道插入数据我们需要生成主键,MyBatis-Plus 提供了很多的主键生成策略,MyBatis-Plus 默认为我们插入的数据生成主键策略是
全局唯一主键:UUID。 - 如果需要修改成主键自增,需要数据库支持主键自增功能
@TableId(type=IdType.AUTO) private Long id;
update方法
根据 ID 修改数据@Test public void updateUser(){ User user = new User(); user.setName("wangwu"); UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper.eq("name","ww"); userMapper.update(user,userUpdateWrapper); }
封装修改条件来修改数据- 创建 User 对象,然后设置需要修改的值
- 根据 userUpdateWrapper 的 eq方法封装修改条件,修改名字等于
ww的用户
@Test public void updateUser(){ User user = new User(); user.setName("wangwu"); UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper.eq("name","ww"); userMapper.update(user,userUpdateWrapper); }
delete方法
删除方法的话,下面都列出了每个方法的作用,删除就分为两种情况:一是有条件删除,而是没有条件删除。
根据id删除
/** * 根据id删除用户 */ @Test public void deleteUserById(){ userMapper.deleteById(6L); }根据id批量删除
/** * 根据id批量删除用户 */ @Test public void deleteBatchById(){ userMapper.deleteBatchIds(Arrays.asList(3L,5L)); }封装Map,每一个key都是where条件
@Test public void deleteUserByMap(){ Map<String,Object> map = new HashMap<>(); map.put("name","zwq"); int result = userMapper.deleteByMap(map); System.out.println(result); map.put("age",39); result = userMapper.deleteByMap(map); System.out.println(result); }封装Wrapper,传入entity充当where条件
/** * 构造条件封装器,传入的entity充当where条件 */ @Test public void deleteUserByWrapper(){ User user = new User(); user.setName("张三"); user.setAge(39); Wrapper wrapper = new QueryWrapper(user); userMapper.delete(wrapper); }
select方法
查询方法的话,下面都列出了每个方法的作用,查询就分为两种情况:一是有条件查询,而是没有条件查询。
- 根据id查找
@Test public void selectUserById(){ System.out.println(userMapper.selectById(1L)); } - 根据id批量查询
@Test public void selectBatchUserById(){ List<User> users = userMapper.selectBatchIds(Arrays.asList(1l, 2l, 3l, 4l, 5l, 6l)); users.forEach(System.out::println); } - 封装Wrapper条件,查询一条数据,超过一条就会报错
/** * 两个eq最终会形成AND */ @Test public void selectOne(){ QueryWrapper<User> wrapper = new QueryWrapper(); wrapper.eq("age",19).eq("name","ls"); User user = userMapper.selectOne(wrapper); System.out.println(user); } - 封装Wrapper条件,查询总数据个数
/** * selectCount * 查询总记录数,参数为null,说明没有条件 * 如果封装Wrapper条件,则会筛选查找总记录数 */ @Test public void selectCount(){ Integer selectCount = userMapper.selectCount(null); System.out.println(selectCount); QueryWrapper<User> wrapper = new QueryWrapper(); wrapper.eq("age",19).eq("name","zwq"); Integer selectCount = userMapper.selectCount(wrapper); System.out.println(selectCount); } - 封装Wrapper条件,查询总数据
```java /** * selectList * 查询全部数据,参数为null,说明没有条件 * 如果封装Wrapper条件,则会筛选查找总记录数 */ @Test public void selectList(){ List<User> users = userMapper.selectList(null); users.forEach(System.out::println); QueryWrapper wrapper = new QueryWrapper(); wrapper.eq("age",18); List<User> users = userMapper.selectList(wrapper); users.forEach(System.out::println); } - 封装Wrapper条件,分页查询数据
分页查询在 MyBatis-Plus 当中需要配置分页插件,不配置,分页不生效@Configuration public class MyBatisPlusConfig { /** * 分页插件 * @return */ @Bean public PaginationInterceptor paginationInterceptor(){ return new PaginationInterceptor(); } }@Test public void selectPage(){ QueryWrapper wrapper = new QueryWrapper(); //年龄大于18 wrapper.gt("age",18); Page<User> page = new Page<>(0,2); IPage<User> userIPage = userMapper.selectPage(page,wrapper); userIPage.getRecords().forEach(System.out::println); }
结合案例讲解 Wrapper 条件封装器
- 重点说明,掌握好 Wrapper 将会省去大量的编码工作,所以耐心看完每一个 Wrapper 代码案例,绝对收获不少。
- Wrapper 条件构造器用于增删改查的时候注入条件筛选。
- 使用 Wrapper 的 API 接口生成 where 条件
- 传入 entity 生成 where 条件
Wrapper 基本操作API
这些 API 最终都会转换为 where 筛选条件。
- eq:等于
@Test public void eq(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //查询年龄为21的用户,age:说明是根据年龄筛选,年龄为21 queryWrapper.eq(false,"age",21); List<User> users = userMapper.selectList(queryWrapper); //List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - ne:不等于
@Test public void ne(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //查询年龄不等于90的用户,age:说明是根据年龄筛选,年龄不等于90 queryWrapper.ne("age",90); List<User> users = userMapper.selectList(queryWrapper); //List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - gt:大于
@Test public void gt(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //查询年龄大于等于90的用户,age:说明是根据年龄筛选,年龄大于等于90 queryWrapper.gt("age",90); List<User> users = userMapper.selectList(queryWrapper); //List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - ge:大于等于
@Test public void ge(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //查询年龄大于等于90的用户,age:说明是根据年龄筛选,年龄大于等于90 queryWrapper.ge("age",90); List<User> users = userMapper.selectList(queryWrapper); //List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - lt:小于
@Test public void lt(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //查询年龄小于90的用户,age:说明是根据年龄筛选,年龄小于90 queryWrapper.lt("age",90); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - le:小于等于
@Test public void le(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //查询年龄小于等于90的用户,age:说明是根据年龄筛选,年龄小于等于90 queryWrapper.le("age",90); List<User> users = userMapper.selectList(queryWrapper); //List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - between:在…之间
@Test public void between(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //查询年龄在90-99的用户,age:说明是根据年龄筛选,年龄在90-99 queryWrapper.between("age",90,99); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - notBetween:不在…之间
@Test public void notBetween(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //查询年龄不在90-99的用户,age:说明是根据年龄筛选,年龄不在90 queryWrapper.notBetween("age",90,99); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - in:包含…
@Test public void in(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //查询年龄是33,90,99的用户,age:说明是根据年龄筛选,年龄是33,90,99 queryWrapper.in("age",90,99,33); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - notIn:不包含…
@Test public void notIn(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //查询年龄不是1,2,3,4,5,6的用户,age:说明是根据年龄筛选,年龄不是1,2,3,4,5,6 queryWrapper.notIn("age",1,2,3,4,5,6); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
模糊查询
模糊查询 API 就是 SQL 当中的模糊查询
- like:包含传入的值。
@Test public void like(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //模糊查询:like("age",33)--> age like %33% queryWrapper.like("age",33); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - notLike:不包含传入的值
@Test public void notLike(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //模糊查询:notLike("age",3)--> age NOT LIKE %3%,年龄不包含3 queryWrapper.notLike("age",3); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - likeLeft
@Test public void likeLeft(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //模糊查询:likeLeft("age",3)--> age LIKE %3,年龄包含3 queryWrapper.likeLeft("age",3); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - likeRight
@Test public void likeRight(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //模糊查询:likeRight("age",3)--> age LIKE 3%,年龄以3开头 queryWrapper.likeRight("age",3); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
判空
- isNull:为空
@Test public void isNull(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //模糊查询:isNull("age")-->查询age为空的字段 queryWrapper.isNull("age"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - isNotNull:不为空
@Test public void isNotNull(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //模糊查询:isNotNull("age")-->查询age不为空的字段 queryWrapper.isNotNull("age"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
排序
- orderBy:升序或者降序
@Test public void orderBy(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); //全部降序排列 queryWrapper.orderBy(true,false,"age"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }@Test public void orderByAsc(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); 全部升序排列 queryWrapper.orderBy(true,true,"age"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - orderAsc:全部升序排列
@Test public void orderByAsc(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.orderByAsc(true,"age","name"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } - orderByDesc:全部降序排列
@Test public void orderByDesc(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.orderByDesc(true,"age","name"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
分组
- groupBy
groupBy(true,"age");-->GROUP BY age
逻辑查询
or:调用OR,表示紧接下一个方法不是用and连接(不调用OR,则默认使用AND连接)
@Test public void or(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name",18).or().eq("name","zwq"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } SELECT id,create_time,name,update_time,email,age FROM user WHERE (name = ? OR name = ?)and:and嵌套
@Test public void and(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name",18).and(wrapper->wrapper.eq("age",21).eq("email","zwq@qq.com")); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } SELECT id,create_time,name,update_time,email,age FROM user WHERE (name = ? AND ( (age = ? AND email = ?) ))
查询指定字段
在 MyBatis-Plus 查询时,默认查询所有的字段,如果有需要也可以通过 select 方法查询指定字段。
- select:查询指定字段
@Test public void select(){ QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("age",21).or().eq("name","zwq").select("age","name","email"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); } SELECT age,name,email FROM user WHERE (age = ? OR name = ?)
MyBatis-Plus 自动填充
- 自动填充功能主要用于新增一条数据或者修改一条数据的时候,对其中某些字段自动设置值,也就是不用我们在程序中显式设置。
- 在阿里手册数据库规范当中,明确要求每一张表都必须存在两个字段,一个就是创建时间
create_time,另一个就是修改时间update_time,这两个字段如果我们需要手动设置值的话也非常容易,就是new Date()即可,假设一个项目上有几百张表,每张表都有这两个字段,一张表有多次修改的业务,这样如果让我们写这些没意义的代码只会降低开发效率,所以这时就可以使用 MyBatis-Plus 自动填充功能。
自动填充使用步骤
- 为实体类字段添加注解以及注解对应属性
fill = FieldFill.INSERT:在 insert 的时候自动填充字段值
fill = FieldFill.INSERT_UPDATE:在 insert 和 update 的时候自动填充字段值@TableField(fill = FieldFill.INSERT) private Date createTime; @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; - 然后我们需要编写自动填充策略类,就是在 insert 或者 update 的时候,自动填充什么样的字段值,然后将给类交给 Spring 管理
@Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { /** * 插入时,自动填充策略 * 为指定字段决定在插入时,填充指定的默认值 * @param metaObject */ @Override public void insertFill(MetaObject metaObject) { log.info("start insert fill..."); this.setFieldValByName("createTime",new Date(),metaObject); this.setFieldValByName("updateTime",new Date(),metaObject); } /** * 更新时,自动填充策略 * 为指定字段决定在更新时,填充指定的默认值 * @param metaObject */ @Override public void updateFill(MetaObject metaObject) { log.info("start update fill..."); this.setFieldValByName("updateTime",new Date(),metaObject); } } - 测试上面配置好的填充策略

MyBatis-Plus 逻辑删除
- 在 delete 表数据的时候,有两钟情况,一是物理删除(真正从数据库表删除数据),二是逻辑删除,就是在删除的时候携带某些条件,比如一张表中新增一个字段(deleted,是否逻辑删除),如果逻辑删除了,就设置为1,如果没有逻辑删除,就设置为0,这样在查询的时候,只要携带deleted为查询条件即可,这样就避免了数据真正被删除。
- 在 MyBatis-Plus 当中,如果为一张表数据配置逻辑删除后,那么以后对这张表任意的记录进行删除操作的时候,都不会真正的删除,而且将deleted字段改为逻辑已删除对应的值。
未逻辑删除情况

逻辑删除使用步骤
- 修改表结构,添加deleted字段,用于表示数据是否被删除,1代表删除,0代表未删除。
ALTER TABLE `user`ADD COLUMN `deleted` int(1) NULL DEFAULT 0 COMMENT '1代表删除,0代表未删除'; - 修改实体类,增加deleted属性并且添加@TableLogic注解
@TableLogic private Integer deleted; - 全局配置逻辑已删除值、逻辑未删除值
mybatis-plus: global-config: db-config: logic-delete-value: 1 #逻辑删除之后设置的值为1 logic-not-delete-value: 0 #未逻辑删除之后设置的值为0 - 测试逻辑删除功能

- 再测试一下逻辑删除之后,查询是怎么样子的

MyBatis-Plus 代码生成器
- MyBatis 也有代码生成器,MyBatis-Plus 也有代码生成器代码生成器,它们两者有什么区别?
MyBatis 的代码生成器可以一次性根据所有数据库表生成代码,而 MyBatis-Plus 的代码生成器只能一次生成一张数据库表的代码,这就是两者区别之处。 - 如果想知道 MyBatis 怎么实现代码生成器,可以看下面一篇博客
MyBatis 代码生成器详细讲解 - 因为文章篇幅的原因,我把 MyBatis-Plus 的代码生成器另外写一篇博客详细说明
MyBatis-Plus 代码生成器详细讲解
总结
- 这篇文章肝了近两万字,相信看完之后,你绝对可以将 MyBatis-Plus 应用到实战当中。
- 如果大家觉得不错,可以点个赞或者关注博主我也行,之后会再接再厉输出好内容文章,感谢!
版权声明:本文为weixin_44176169原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。