#Mybatis-Plus

Mybatis-Plus介绍

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发 提 高效率而生。该框架由baomidou(苞米豆)组织开发并且开源的。

官网:https://mybatis.plus/https://mp.baomidou.com/

github地址: https://github.com/baomidou/mybatis-plus \

码云地址:https://gitee.com/baomidou/mybatis-plus

我们的愿景是成为 MyBatis 最好的搭档,就像 魂斗罗 中的 1P 2P,基友搭配,效率翻倍。

支持的数据库

MyBatisPlus支持如下数据库:

  • mysql`` mariadb ``oracle`` db2`` h2`` hsql`` sqlite`` postgresql`` sqlserver

  • 达梦数据库 虚谷数据库 人大金仓数据库

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

  • 损耗小:启动即会自动注入基本 CRUD,性能基本无损耗,直接面向对象操作

  • 强大的 CRUD 操作:内置通用 Mapper 通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作, 更有强大的条件构造器,满足各类使用需求

  • 支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错

  • 支持多种数据库:支持 MySQL MariaDB Oracle DB2 H2 HSQL SQLite Postgre SQLServer2005 SQLServer 等多种数据库

  • 支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美 解决主键问题1

  • 支持 XML 热加载:Mapper 对应的 XML 支持热加载,对于简单的 CRUD 操作,甚至可以无 XML 启动

  • 支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作

  • 支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )

  • 支持关键词自动转义:支持数据库关键词(order key……)自动转义,还可自定义关键词

  • 内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper Model Service Controller 层代码,支 持模板引擎,更有超多自定义配置等您来使用

  • 内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询

  • 内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询

  • 内置全局拦截插件:提供全表 delete update 操作智能分析阻断,也可自定义拦截规则,预防误操作

  • 内置 Sql 注入剥离器:支持 Sql 注入剥离,有效预防 Sql 注入攻击

    架构

Mybatis主要包含以下模块:

核心功能(core):基于Mybatis的封装,提供了Mybatis Plus的基础配置类与核心功能,如内置通用 Mapper, Lambda 表达式查询等。

注解(annotation):提供了Mybatis Plus中注解的定义。

扩展功能(extension):提供扩展及插件功能,包括分页插件 通用 Service扩展 性能分析插件等。

代码生成器(generator):通过代码生成器可以快速生成 Mapper接口 Entity实体类 Mapper XML Service

Controller 等各个模块的代码,极大的提升了开发效率。

执行流程:

  1. 扫描注解Entity,反射提取注解信息如:表名称 字段名称等信息。
  2. 分析注解信息并基于com.baomidou.mybatisplus.core.enums的SQL模板生成基本CRUD SQL。
  3. 最后将这些SQL注入到Mybatis环境中。

因此Mybatis plus无需编写CRUD SQL语句,只需继承BaseMapper,魔术般的拥有了CRUD功能(通用CRUD)

快速入门

准备环境

  • JDK 8+

  • Maven 3.6.1

  • IDEA 2020.1.2

  • MySQL5.7

创建数据库以及表

创建数据库并设置字符集为utf-8

1
CREATE DATABASE `mybatis` CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';

创建表和测试数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
DROP TABLE IF EXISTS user;

CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);


INSERT INTO user (id, name, age, email) VALUES
(1, '伽罗', 18, 'zysheep@126.com'),
(2, '韩信', 36, 'zysheep@126.com'),
(3, '李白', 28, 'zysheep@126.com'),
(4, '武则天', 21, 'zysheep@126.com'),
(5, '嬴政', 24, 'zysheep@126.com');

工程搭建

使用Spring Initializr初始化器快速创建SpringBoot项目

pom.xml

Spring boot: 2.2.2.RELEASE,mybatis-plus:3.1.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>cn.zysheep</groupId>
<artifactId>springboot-06-data-mybatis-plus</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-06-data-mybatis-plus</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<!-- druid-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!-- druid-->
<!-- mysql-connector-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- mysql-connector-->
<!-- mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.1.1</version>
</dependency>
<!-- mybatis-plus-->




<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<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>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

编写application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# DataSource Config
spring:
datasource:
# 数据源基本配置
url: jdbc:mysql://172.16.0.192:3306/mybatis
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
initialization-mode: always #表示始终都要执行初始化,2.x以上版本需要加上这行配置
# 自动生成表
schema:
- classpath:db/schema-h2.sql
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

# Logger Config
logging:
level:
cn.zysheep.springboot: debug

entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("user")
public class User implements Serializable {
@TableId("ID")
private Long id;
@TableField("NAME")
private String name;
@TableField("age")
private Integer age;
@TableField("email")
private String email;
}
  • @Data:lombok的注解,使用它可以省略getter/setter方法。

  • @NoArgsConstructor: 生成无参构造 方法

  • @AllArgsConstructor:生成所有参数构造 方法,参数顺序与属性定义顺序一致。

  • @TableName:指定表名

  • @TableId:指定主键名

  • @TableField:指定列名

    内容不区分大小写

编写mapper

1
2
3
public interface UserMapper extends BaseMapper<User> {

}

编写启动类

1
2
3
4
5
6
7
8
@SpringBootApplication
@MapperScan("cn.zysheep.springboot.mapper") //设置mapper接口的扫描包
public class Springboot06DataMybatisPlusApplication {

public static void main(String[] args) {
SpringApplication.run(Springboot06DataMybatisPlusApplication.class, args);
}
}

编写测试用例

编写UserMapper的测试用例 ,使用UserMapper查询用户列表。

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @author: 三月三
* @description: 测试查询所有数据
* @param: []
* @return: void
*/
@Test
public void testSelect() {
List<User> userList = userMapper.selectList(null);
Assert.assertEquals(5, userList.size());
userList.forEach(System.out::println);
}

测试:

1
2
3
4
5
6
7
8
2020-06-09 15:50:40.358 DEBUG 7736 --- [           main] c.z.s.mapper.UserMapper.selectList       : ==>  Preparing: SELECT ID,NAME,age,email FROM user 
2020-06-09 15:50:40.397 DEBUG 7736 --- [ main] c.z.s.mapper.UserMapper.selectList : ==> Parameters:
2020-06-09 15:50:40.450 DEBUG 7736 --- [ main] c.z.s.mapper.UserMapper.selectList : <== Total: 5
User(id=1, name=伽罗, age=18, email=zysheep@126.com)
User(id=2, name=韩信, age=36, email=zysheep@126.com)
User(id=3, name=李白, age=28, email=zysheep@126.com)
User(id=4, name=武则天, age=21, email=zysheep@126.com)
User(id=5, name=嬴政, age=24, email=zysheep@126.com)

常见配置

在MP中有大量的配置,其中有一部分是Mybatis原生的配置,另一部分是MP的配置,详情: https://mybatis.plus/confifig/

confifigLocations

confifigLocations即MyBatis 配置文件位置,如果您有单独的 MyBatis 配置,请将其路径配置到 confifigLocation 中。 MyBatis Confifiguration 的具体内容请参考MyBatis 官方文档

示例:

  1. 在resources下创建mybatis-confifig.xml

    1
    2
    3
    4
    <?xml version="1.0" encoding="UTF‐8" ?> <!DOCTYPE configuration PUBLIC "‐//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis‐3‐config.dtd"> 
    <configuration>

    </configuration>
  2. 在application.yml下配置confifigLocations,如下:

    1
    2
    mybatis-plus:
    config-location: classpath:mybatis‐config.xml

mapperLocations

mapperLocations即MyBatis Mapper 所对应的 mapper配置 文件位置,如果您在 Mapper 中有自定义方法(XML 中有自定义实现),需要进行该配置,告诉 Mapper 所对应的 XML 文件位置。 如果不配置mapperLocations时,mapper的xml文件存放路径需要和mapper class文件保持一致,文件名保持 一 致

1
2
mybatis-plus:
mapper-locations: classpath*:mybatis/mapper/*.xml

Maven 多模块项目的扫描路径需以 classpath*: 开头 (即加载多个 jar 包下的 XML 文件)

typeAliasesPackage

设置MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名,注册后在 Mapper 对应的 XML 文件中可以直接使用类名,而不用使用全限定的类名(即 XML 中调用的时候不用包含包名)。

1
2
mybatis‐plus:
type‐aliases‐package: cn.zysheep.springboot.model

mapUnderscoreToCamelCase

是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN(下划线命名) 到经典 Java 属性名 aColumn(驼峰命名) 的类似映射。 默认值:true

注意: 在 MyBatis-Plus 中此属性默认值为true,用于生成最终的 SQL 语句 如果您的数据库命名符合规则无需使用 @TableField 注解指定数据库字段名

1
2
3
#开启自动驼峰映射,注意:配置configuration.map‐underscore‐to‐camel‐case则不能配置config‐location mybatis‐plus:
configuration:
map‐underscore‐to‐camel‐case: true

通用CRUD

通过前面的学习,我们了解到通过继承BaseMapper就可以获取到各种各样的单表操作,接下来我们将详细讲解这 些操作,下图是BaseMapper的各各方法:

插入操作

测试用例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @author: 三月三
* @description: 新增记录
* @param: []
* @return: void
*/
@Test
public void testInsert() {
User user = new User();
user.setName("孙尚香");
user.setAge(20);
user.setEmail("zysheep@126.com");
assertThat(userMapper.insert(user)).isGreaterThan(0); ////返回的result是受影响的行数,并不是自增后的id
// 成功直接拿会写的 ID
assertThat(user.getId()).isNotNull();
//assertThat() 是 Assert 的一个精通方法,用来比对返回结果
}

MP主键生成策略

上例中Mybatis-plus自动生成ID,如何设置id的生成策略呢?

MP支持的id策略如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.baomidou.mybatisplus.annotation;

public enum IdType {
//数据库ID自增
AUTO(0),
//该类型为未设置主键类型
NONE(1),
// 用户输入ID 该类型可以通过自己注册自动填充插件进行填充
INPUT(2),
//全局唯一ID (idWorker)
ID_WORKER(3),
//全局唯一ID (UUID)
UUID(4),
// 字符串全局唯一ID (idWorker 的字符串表示)
ID_WORKER_STR(5);

private final int key;

private IdType(int key) {
this.key = key;
}

public int getKey() {
return this.key;
}
}

更新操作

根据id更新

1
2
3
4
5
/**
* 根据 ID 修改
** @param entity 实体对象
*/
int updateById(@Param(Constants.ENTITY) T entity);

根据id更新操作步骤:

  1. 首先需要设置对象的主键属性值

  2. 再设置要更新的属性值。

  3. 根据主键找到对象,更新设置属性值。

  4. 返回影响的记录数。

    注意:只能将对象中不为NULL的属性更新到表中。

1
2
3
4
5
6
7
@Test public void testUpdateById() {
User user = new User();
user.setId(6L);//主键
user.setAge(21); // 更新的字段
// 根据id更新,更新不为null的字段
this.userMapper.updateById(user);
}

根据条件更新

1
2
3
4
5
6
/**
* 根据 whereEntity 条件,更新记录
** @param entity 实体对象 (set 条件值,可以为 null)
* @param updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
*/
int update(@Param(Constants.ENTITY) T entity, @Param(Constants.WRAPPER) Wrapper<T> updateWrapper);

根据ID更新一次只能更新一条记录,根据条件更新可实现批量更新。

根据条件更新步骤:

  1. 在对象中设置要更新的属性值。
  2. 设置QueryWrapper,设置更新条件,可以设置多个。
  3. 返回影响的记录数。

注意:只能将对象中不为NULL的属性更新到表中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @author: 三月三
* @description: 修改操作
* @param: []
* @return: void
*/
@Test public void testUpdate() {
User user = new User();
user.setAge(22); //更新的字段
//更新的条件
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.eq("name", "孙尚香");
//可以设置多个条件...

//执行更新操作
int result = this.userMapper.update(user, wrapper);
System.out.println("result = " + result);
}

上边根据id更新 根据条件更新的方法只能将对象中不为NULL的属性更新到表中,下边通过UpdateWrapper进行更 新,将email字段更新为NULL.

1
2
3
4
5
6
7
8
9
//UpdateWrapper进行更新,将email字段更新为NULL.
@Test public void testUpdate2() {
//更新的条件以及字段
UpdateWrapper<User> wrapper = new UpdateWrapper<>();
wrapper.eq("id", 4).set("age", 23).set("email",null);
//执行更新操作
int result = this.userMapper.update(null, wrapper);
System.out.println("result = " + result);
}

删除操作

deleteById

方法定义:

1
2
3
4
5
/**
* 根据 ID 删除
** @param id 主键ID
*/
int deleteById(Serializable id);

操作步骤:

  1. 指定要删除记录的主键值
  2. 调用deleteById方法执行删除。

测试用例:

1
2
3
4
5
6
@Test 
public void testDeleteById() {
//执行删除操作
int result = this.userMapper.deleteById(6L);
System.out.println("result = " + result);
}

delete

方法定义:

1
2
3
4
5
/**
* 根据 entity 条件,删除记录
** @param wrapper 实体对象封装操作类(可以为 null)
*/
int delete(@Param(Constants.WRAPPER) Wrapper<T> wrapper);

根据条件删除步骤

  1. 定义对象,设置属性值,指定删除条件 ,可指定多个删除条件

  2. 设置QueryWrapper

  3. 执行删除

删除条件只匹配对象中不为NULL的属性值

1
2
3
4
5
6
7
8
9
@Test public void testDeleteByMap() {
User user = new User();
user.setAge(20);
user.setName("李白");
//将实体对象进行包装,包装为操作条件
QueryWrapper<User> wrapper = new QueryWrapper<>(user);
int result = this.userMapper.delete(wrapper);
System.out.println("result = " + result);
}

deleteBatchIds

方法定义:

1
2
3
4
5
/**
* 删除(根据ID 批量删除)
** @param idList 主键ID列表(不能为 null 以及 empty)
*/
int deleteBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

批量删除操作步骤:

  1. 指定 id列表
  2. 执行删除
1
2
3
4
5
6
@Test
public void testDeleteByIds() {
//根据id集合批量删除
int result = this.userMapper.deleteBatchIds(Arrays.asList(1L,10L,20L));
System.out.println("result = " + result);
}

查询操作

selectById

1
2
3
4
5
/*
** 根据 ID 查询
** @param id 主键ID
*/
T selectById(Serializable id);

根据id查询步骤:

  1. 设置查询记录的主键值。

  2. 执行查询。

  3. 查询结果返回一个对象。

    1
    2
    3
    4
    5
    6
    @Test
    public void testSelectById() {
    //根据id查询数据
    User user = this.userMapper.selectById(2L);
    System.out.println("result = " + user);
    }

selectBatchIds

方法定义:

1
2
3
4
5
/*
** 查询(根据ID 批量查询)
** @param idList 主键ID列表(不能为 null 以及 empty)
*/
List<T> selectBatchIds(@Param(Constants.COLLECTION) Collection<? extends Serializable> idList);

根据id列表查询:

  1. 设置id列表
  2. 执行查询
  3. 查询对象返回List
1
2
3
4
5
6
7
@Test public void testSelectBatchIds() {
//根据id集合批量查询
List<User> users = this.userMapper.selectBatchIds(Arrays.asList(2L, 3L, 4L));
for (User user : users) {
System.out.println(user);
}
}

selectOne

方法定义:

1
2
3
4
5
/*
** 根据 entity 条件,查询一条记录
** @param queryWrapper 实体对象封装操作类(可以为 null)
*/
T selectOne(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

查询步骤:

  1. 设置QueryWrapper对象,设置查询条件,可以设置多个条件
  2. 执行查询

注意:如果查询结果为多条记录则报错(TooManyResultsException)

1
2
3
4
5
6
7
@Test public void testSelectOne() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.eq("name", "李白");
//根据条件查询一条数据,如果结果超过一条会报错
User user = this.userMapper.selectOne(wrapper);
System.out.println(user);
}

selectCount

方法定义:

1
2
3
4
5
/*
** 根据 Wrapper 条件,查询总记录数
** @param queryWrapper 实体对象封装操作类(可以为 null)
*/
Integer selectCount(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

测试:

1
2
3
4
5
6
7
8
@Test public void testSelectCount() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.gt("age", 20);
//年龄大于23岁
// 根据条件查询数据条数
Integer count = this.userMapper.selectCount(wrapper);
System.out.println("count = " + count);
}

selectList

方法定义:

1
2
3
4
5
/*
** 根据 entity 条件,查询全部记录
** @param queryWrapper 实体对象封装操作类(可以为 null)
*/
List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

测试用例:

1
2
3
4
5
6
7
8
9
10
@Test public void testSelectList() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.gt("age", 20);
//年龄大于23岁
// 根据条件查询数据
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println("user = " + user);
}
}

selectPage

方法定义:

1
2
3
4
5
6
/*
** 根据 entity 条件,查询全部记录(并翻页)
** @param page 分页查询条件(可以为 RowBounds.DEFAULT)
* @param queryWrapper 实体对象封装操作类(可以为 null)
*/
IPage<T> selectPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

配置分页插件:

1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@MapperScan("cn.zysheep.springboot.mapper")
public class MybatisPlusConfig {

/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}

测试用例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test public void testSelectPage() {
QueryWrapper<User> wrapper = new QueryWrapper<User>();
wrapper.gt("age", 20);
//年龄大于20岁
// 参数1:当前页码,小于1的按1算
// 参数2:每页记录数
Page<User> page = new Page<>(1,2);
//根据条件查询数据
IPage<User> iPage = this.userMapper.selectPage(page, wrapper);
System.out.println("数据总条数:" + iPage.getTotal());
System.out.println("总页数:" + iPage.getPages());
//取出分页记录
List<User> users = iPage.getRecords();
for (User user : users) {
System.out.println("user = " + user);
}
}

#条件构造器

在MP中,Wrapper接口的实现类关系如下:

在MP查询中,还可以使用lambda方式查询,降低数据库列表写错的风险。

基本比较操作

eq 等于 =
ne 不等于 <>
gt 大于 >
ge 大于等于 >=
lt 小于 <
le 小于等于 <=
between BETWEEN 值1 AND 值2
notBetween NOT BETWEEN 值1 AND 值2
in 字段 IN (value.get(0), value.get(1), …)
notIn 字段 NOT IN (v0, v1, …)

测试

1
2
3
4
5
6
7
8
9
@Test public void testEq() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,password,name,age,email FROM tb_user WHERE age >= ? AND name IN (?,?,?)
wrapper .ge("age", 20) .in("name", "李白", "韩信", "赵六");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

Lambda方式构造条件:

1
2
3
4
5
6
7
8
9
@Test public void testLombokEq() {
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
//SELECT id,user_name,password,name,age,email FROM tb_user WHERE age >= ? AND name IN (?,?,?)
wrapper .ge(User::getAge, 20) .in(User::getName, "李白", "韩信", "赵六");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

模糊查询

like LIKE ‘%值%’ 例: like(“name”, “王”) —> name like ‘%王%’
notLike NOT LIKE ‘%值%’ 例: notLike(“name”, “王”) —> name not like ‘%王%’
likeLeft LIKE ‘%值’ 例: likeLeft(“name”, “王”) —> name like ‘%王’
likeRight LIKE ‘值%’ 例: likeRight(“name”, “王”) —> name like ‘王%

测试用例:

1
2
3
4
5
6
7
8
9
10
@Test public void testWrapper() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,password,name,age,email FROM tb_user WHERE name LIKE ?
// Parameters: %五%(String)
wrapper.like("name", "白");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

逻辑查询

or 拼接 OR 主动调用 or 表示紧接着下一个方法不是用 and 连接!(不调用 or 则默认为使用 and 连接)
and AND 嵌套 例: and(i -> i.eq(“name”, “李白”).ne(“status”, “活着”)) —> and (name = ‘李白’ and status <>
1
2
3
4
5
6
7
8
9
10
@Test public void testWrapper() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,password,name,age,email FROM user WHERE name = ? OR age = ?
wrapper.eq("name","李白").or().eq("age", 24);
//变为and方式 wrapper.eq("name","李四").eq("age", 24)
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

Lambda方式构造条件

1
2
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); 
wrapper.eq(User::getName,"李四").or().eq(User::getAge, 24);

select

在MP查询中,默认查询所有的字段,如果有需要也可以通过select方法进行指定字段。不指定的字段为null

1
2
3
4
5
6
7
8
9
10
@Test public void testWrapperSelectValue() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,name,age FROM user WHERE name = ? OR age = ?
wrapper.eq("name", "李白") .or() .eq("age", 24) .select("id", "name", "age");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}

}

Lambda方式构造条件:

1
2
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); 
wrapper.eq(User::getName, "李白") .or() .eq(User::getAge, 24) .select(User::getId, User::getName, User::getAge);

排序

  • orderByAsc
    • 升序排序
    • 参数:变长数组,设置多个字段名
    • 例: orderByAsc(“id”, “name”) —> order by id ASC,name ASC
  • orderByDesc
    • 降序排序
    • 参数:变长数组,设置多个字段名
    • 例: orderByDesc(“id”, “name”) —> order by id DESC,name DESC
  • orderBy
    • orderBy(boolean condition, boolean isAsc, R... columns)
    • 自定义排序规则
    • 参数1:true有效,false无效 ,参数2:是否升序,参数3..设置多个字段

测试:

1
2
3
4
5
6
7
8
9
@Test public void testWrapperOrderBy () {
QueryWrapper<User> wrapper = new QueryWrapper<>();
//SELECT id,user_name,password,name,age,email FROM tb_user ORDER BY age DESC
wrapper.orderByDesc("age");
List<User> users = this.userMapper.selectList(wrapper);
for (User user : users) {
System.out.println(user);
}
}

Lambda方式构造条件:

1
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>(); wrapper.orderByDesc(User::getAge);

代码生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Mapper接口、 Entity实体类 及Mapper XML文件、 Service 、Controller 等各个模块的代码,极大的提升了开发效率。

1)在pom文件中引入依赖

1
2
3
4
5
<dependency> 
<groupId>com.baomidou</groupId>
<artifactId>mybatis‐plus‐generator</artifactId>
<version>3.1.0</version>
</dependency

2)配置相关信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package cn.zysheep.generator;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
* @version v1.0
* @ProjectName: springboot-learning-examples
* @ClassName: MyBatisPlusGenerator
* @Description: MyBatis Plus Generator 配置执行类示例
* @Author: 三月三
*/
public class MyBatisPlusGenerator {
/**
* <p>
* 读取控制台内容
* </p>
*/
public static String scanner(String tip) {
Scanner scanner = new Scanner(System.in);
StringBuilder help = new StringBuilder();
help.append("请输入" + tip + ":");
System.out.println(help.toString());
if (scanner.hasNext()) {
String ipt = scanner.next();
if (StringUtils.isNotEmpty(ipt)) {
return ipt;
}
}
throw new MybatisPlusException("请输入正确的" + tip + "!");
}

public static void main(String[] args) {
// 代码生成器
AutoGenerator autoGenerator = new AutoGenerator();

// 全局配置
GlobalConfig globalConfig = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
//当前项目名
String projectName = "/generator";

globalConfig.setOutputDir(projectPath + projectName+"/src/main/java");
globalConfig.setAuthor("author");
globalConfig.setOpen(false);
globalConfig.setIdType(IdType.ID_WORKER);
autoGenerator.setGlobalConfig(globalConfig);

// 数据源配置 需配置
DataSourceConfig dataSourceConfig = new DataSourceConfig();


// 交易服务
dataSourceConfig
.setUrl("jdbc:mysql://172.16.0.192:3306/mybatis?serverTimezone=Asia/Shanghai");

dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("123456");
autoGenerator.setDataSource(dataSourceConfig);

// 生成包配置
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("cn.zysheep");
//如果需要手动输入模块名
packageConfig.setModuleName(scanner("模块名"));
autoGenerator.setPackageInfo(packageConfig);

// 自定义配置
InjectionConfig injectionConfig = new InjectionConfig() {
@Override
public void initMap() {
// to do nothing
}
};

// 如果模板引擎是 freemarker
String templatePath = "/templates/mapper.xml.ftl";

// 自定义输出配置
List<FileOutConfig> focList = new ArrayList<>();

// 自定义配置会被优先输出
focList.add(new FileOutConfig(templatePath) {
@Override
public String outputFile(TableInfo tableInfo) {

// 自定义输出文件名
return projectPath + projectName+"/src/main/resources/mapper/" + packageConfig.getModuleName()
+ "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
}
});

injectionConfig.setFileOutConfigList(focList);
autoGenerator.setCfg(injectionConfig);

// 配置模板
TemplateConfig templateConfig = new TemplateConfig();

// 配置自定义输出模板
//指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
// templateConfig.setEntity("templates/entity-test.java");
// templateConfig.setService("templates/service.java");
// templateConfig.setController("templates/controller.java");

templateConfig.setXml(null);
autoGenerator.setTemplate(templateConfig);

// 策略配置
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setNaming(NamingStrategy.underline_to_camel);//表名映射到实体策略,带下划线的转成驼峰
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);//列名映射到类型属性策略,带下划线的转成驼峰

strategyConfig.setEntityLombokModel(true);//实体类使用lombok


// 如果 setInclude() //设置表名不加参数, 会自动查找所有表
// 如需要制定单个表, 需填写参数如: strategyConfig.setInclude("user_info);
strategyConfig.setInclude();


//自动将数据库中表名为 user_info 格式的转为 UserInfo 命名
strategyConfig.setTablePrefix(packageConfig.getModuleName() + "_");//表名映射到实体名称去掉前缀
strategyConfig.setEntityBooleanColumnRemoveIsPrefix(true);// Boolean类型字段是否移除is前缀处理
autoGenerator.setStrategy(strategyConfig);
autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
System.out.println("===================== MyBatis Plus Generator ==================");

autoGenerator.execute();

System.out.println("================= MyBatis Plus Generator Execute Complete ==================");
}

}

3)测试生成代码

  1. 运行MyBatisPlusGenerator的main方法。

  2. 输入模块名:

  3. 注意:模块名匹配表名前缀会自动去掉,否则生成的模型类保留前缀。