MyBatis Plus详细教程

Posted Code_Xiaotian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatis Plus详细教程相关的知识,希望对你有一定的参考价值。

目录

一、什么是MybatisPlus

二、快速入门

2.1、创建数据库mybatis_plus

2.2、创建user表

2.3、插入数据

2.4、初始化项目

2.5、添加依赖

2.6、配置(连接数据库)

2.7、编码

2.8、开始使用

2.9、小结

三、配置日志

四、CRUD

4.1、插入测试

4.2、自定义ID生成器

4.2.1、UUID

4.2.2、SnowFlake(雪花算法)

4.3、更新操作

五、自动填充

5.1、什么是自动填充

5.2、自动填充方式

六、乐观锁和悲观锁

6.1、什么是乐观锁

6.2、什么是悲观锁

6.3、配置乐观锁

6.3.1、数据库中添加version字段

6.3.2、同步实体类

6.3.3、配置插件

6.3.4、测试乐观锁

七、增删改查

7.1、查询操作

7.2、分页查询

7.3、删除操作

7.4、逻辑删除

八、执行SQL分析打印

8.1、p6spy依赖引入

8.2、application.yml配置

8.3、spy.properties配置

8.4、测试

九、条件构造器

9.1、代码演示

十、代码自动生成器

10.1、EasyCode

10.2、功能

10.3、操作


一、什么是MybatisPlus

为什么要学MybatisPlus?

MybatisPlus可以节省大量时间,所有的CRUD代码都可以自动化完成

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 操作智能分析阻断,也可自定义拦截规则,预防误操作

二、快速入门

2.1、创建数据库mybatis_plus

2.2、创建user表

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)
);

2.3、插入数据

DELETE FROM user;
​
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.4、初始化项目

快速初始化一个空的spring boot 项目

2.5、添加依赖

引用spring boot starter 父工程

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.5</version>
    <relativePath/>
</parent>

引入spring-boot-starter、spring-boot-starter-test、mybatis-plus-boot-starter、h2依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.1</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>
</dependencies>

注意:尽量不要同时导入mybatis和mybatis_plus,版本差异

2.6、配置(连接数据库)

在application.yml配置文件中添加MySQL数据库的相关配置:

# DataSource Config
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql:///mybatis_plus?userUnicode=true&characterEncoding=utf-8
    driver-class-name: com.mysql.cj.jdbc.Driver

在spring boot启动类中添加@MapperScan注解,扫描Mapper文件夹:

@SpringBootApplication
@MapperScan("com.wen.mybatis_plus.mapper")  //扫描mapper
public class MybatisPlusApplication 
​
    public static void main(String[] args) 
        SpringApplication.run(MybatisPlusApplication.class, args);
    
​

2.7、编码

编写实体类User.java(此处使用Lombok简化代码)

import lombok.Data;
​
@Data
public class User 
    private Long id;
    private String name;
    private Integer age;
    private String email;

编写Mapper包下的UserMapper接口

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wen.mybatis_plus.pojo.User;
import org.apache.ibatis.annotations.Mapper;
​
//再对应的mapper上面实现基本的接口 BaseMapper
@Mapper
public interface UserMapper extends BaseMapper<User> 
    //所有的CRUD都已经完成
    //不需要像以前一样配置一大堆文件:pojo-dao(连接mybatis,配置mapper.xml文件)==>service-controller

注意:

要在主启动类上去扫描mapper包下的所有接口:@MapperScan("com.wen.mybatis_plus.mapper")

2.8、开始使用

添加测试类,进行功能测试:

@SpringBootTest
class MybatisPlusApplicationTests 
​
    //继承了BaseMapper所有的方法,可以编写自己的扩展方法
    @Autowired
    private UserMapper userMapper;
​
    @Test
    public void testSelect()
        System.out.println("--------selectAll method test-------");
        //查询全部用户,参数是一个Wrapper,条件构造器,先不使用为null
        List<User> userList = userMapper.selectList(null);
        userList.forEach(System.out::println);
    

提示:

UserMapper中的selectList()方法的参数为MP内置的条件封装器Wrapper,所以不填写就是无任何条件

控制台输出:

User(id=1, name=Jone, age=18, email=test1@baomidou.com) User(id=2, name=Jack, age=20, email=test2@baomidou.com) User(id=3, name=Tom, age=28, email=test3@baomidou.com) User(id=4, name=Sandy, age=21, email=test4@baomidou.com) User(id=5, name=Billie, age=24, email=test5@baomidou.com)

2.9、小结

以上几个步骤就已经实现User表的CRUD功能,甚至连XML文件都不用编写,以上步骤可以看出集成MyBatis-Plus非常的简单,只需要引入starter工程,并配置mapper扫描路径即可。方法都是MyBatis-Plus写好的,直接引用即可。

三、配置日志

所有的SQL都是不可见的,所以在后台是希望看到SQL是怎么执行的,就必须要配置日志。

在.yml配置文件中配置日志:

#配置日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

四、CRUD

4.1、插入测试

//测试插入
@Test
public void testInsert()
    User user = new User();
    user.setName("小文");
    user.setAge(21);
    user.setEmail("2312103645@qq.com");
​
    int insert = userMapper.insert(user);//如果没有设置id,那么会自动生成id
    System.out.println(insert);//受影响行数
    System.out.println(user);//id会自动回填

 

数据库插入ID默认值为全局唯一ID

4.2、自定义ID生成器

在复杂分布式系统中,往往需要大量的数据和消息进行唯一标识。比如支付宝每一个账号在数据库分表后都需要有一个唯一ID做标识。此时一个能够生成全局唯一ID的系统是非常必要的。

所以,生成的ID需要具备一下特点:

  1. 全局唯一性:不能出现重复的ID号,既然是唯一标识,这是最基本的要求。

  2. 趋势递增:在MySQL InnoDB引擎中使用的是聚集索引,由于多数RDBMS使用B-tree的数据结构来存储索引数据,在主键的选择上面我们应该尽量使用有序的主键保证写入性能。

  3. 单调递增:保证下一个ID一定大于上一个ID,例如事务版本号、IM增量消息、排序等特殊需求。

  4. 信息安全:如果ID是连续的,恶意用户的扒取工作就非常容易做了,直接按照顺序下载指定URL即可;如果是订单号就更危险了,竞对可以直接知道我们一天的单量。所以在一些应用场景下,会需要ID无规则、不规则。

上述123对应三类不同的场景,3和4需求还是互斥的,无法使用同一个方案满足。

在这里只讲两种自动生成ID的方案UUID和SnowFlake

可以查看有哪些方法,查看源码:

在用户ID上添加@TableId注解,里面的值便是使用主键自动生成的方法

自 3.3.0 开始,默认使用雪花算法+UUID(不含中划线)

@Data
public class User 
    //对应数据库中的主键(UUID、自增id、雪花算法、redis、zookeeper)
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    private Integer age;
    private String email;

点击 IdType查看源码看有哪些自动生成方法

/**
 * 生成ID类型枚举类
 *
 * @author hubin
 * @since 2015-11-10
 */
@Getter
public enum IdType 
    /**
     * 数据库ID自增
     * <p>该类型请确保数据库设置了 ID自增 否则无效</p>
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
     */
    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */
    INPUT(2),
​
    /* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 分配ID (主键类型为number或string),
     * 默认实现类 @link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator(雪花算法)
     *
     * @since 3.3.0
     */
    ASSIGN_ID(3),
    /**
     * 分配UUID (主键类型为 string)
     * 默认实现类 @link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator(UUID.replace("-",""))
     */
    ASSIGN_UUID(4);
​
    private final int key;
​
    IdType(int key) 
        this.key = key;
    
   

4.2.1、UUID

UUID(Universally Unique Identifier)的标准型式包含32个16进制数字,以连字号分为五段,形式为8-4-4-4-12的36个字符,示例:550e8400-e29b-41d4-a716-446655440000,到目前为止业界一共有5种方式生成UUID,详情见IETF发布的UUID规范 A Universally Unique IDentifier (UUID) URN Namespace

优点:

  • 性能非常高:本地生成,没有网络消耗。

缺点:

  • 没有排序,无法保证趋势递增。

  • UUID往往使用字符串存储,查询的效率比较低。

  • 不易于存储:UUID太长,16字节128位,通常以36长度的字符串表示,很多场景不适用。

  • 信息不安全:基于MAC地址生成UUID的算法可能会造成MAC地址泄露,这个漏洞曾被用于寻找梅丽莎病毒的制作者位置。

  • ID作为主键时在特定的环境会存在一些问题,比如做DB主键的场景下,UUID就非常不适用:

    • MySQL官方有明确的建议主键要尽量越短越好[4],36个字符长度的UUID不符合要求。

    • 对MySQL索引不利:如果作为数据库主键,在InnoDB引擎下,UUID的无序性可能会引起数据位置频繁变动,严重影响性能。

4.2.2、SnowFlake(雪花算法)

这种方案大致来说是一种以划分命名空间(UUID也算,由于比较常见,所以单独分析)来生成ID的一种算法,这种方案把64-bit分别划分成多段,分开来标示机器、时间等,比如在snowflake中的64-bit分别表示如下图(图片来自网络)所示:

41-bit的时间可以表示(1L<<41)/(1000L360024*365)=69年的时间,10-bit机器可以分别表示1024台机器。如果我们对IDC划分有需求,还可以将10-bit分5-bit给IDC,分5-bit给工作机器。这样就可以表示32个IDC,每个IDC下可以有32台机器,可以根据自身需求定义。12个自增序列号可以表示2^12个ID,理论上snowflake方案的QPS约为409.6w/s,这种分配方式可以保证在任何一个IDC的任何一台机器在任意毫秒内生成的ID都是不同的。

核心思想:

使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID),最后还有一个符号位,永远是0,。

优点:

  • 毫秒数在高位,自增序列在低位,整个ID都是趋势递增的。

  • 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成ID的性能也是非常高的。

  • 可以根据自身业务特性分配bit位,非常灵活。

缺点:

  • 强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。

4.3、更新操作

所有的SQL都是自动配置的

//测试更新
@Test
public void testUpdate()
    User user = new User();
    //可以通过条件自动拼接动态SQL
    user.setId(5L);
    user.setName("id:5,修改过后");
    //updateById 参数是一个对象!
    int i = userMapper.updateById(user);
    System.out.println(i);

注意:updateById 参数是一个对象!而不是ID

 

五、自动填充

5.1、什么是自动填充

在常用业务中有些属性需要配置一些默认值,MyBatis-Plus提供了实现此功能的插件,也就是自动填充功能。比如创建时间、修改时间这些操作一般都是自动化完成的,是不用去手动更新的。

5.2、自动填充方式

方式一:数据库级别(不建议使用)

1、在表中新增字段create_time,update_time

注意:在create_time里除了没有勾选根据当前时间戳更新外其他步骤都一样!

2、在此测试插入方法,需要将实体类同步!!

private Data createTime;
private Data updateTime;

3、在此更新查看

//测试更新
@Test
public void testUpdate()
    User user = new User();
    //可以通过条件自动拼接动态SQL
    user.setId(5l);
    user.setName("id:5,修改过后");
    user.setAge(25);
    //updateById 参数是一个对象!
    int i = userMapper.updateById(user);
    System.out.println(i);

4、查看时间戳是否更新

方式二:代码级别 

1、删除数据库的默认值,更新操作

2、注解填充字段 @TableField(.. fill = FieldFill.INSERT) 生成器策略部分也可以配置!

//注解填充字段 @TableField(.. fill = FieldFill.INSERT) 生成器策略部分也可以配置!
@TableField(fill = FieldFill.INSERT)
private Data createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Data updateTime;

3、自定义实现类 MyMetaObjectHandler 处理这个注解

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler 
    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) 
        log.info("start intsert fill ....");
        //strictInsertFill(MetaObject metaObject, String fieldName, Class<T> fieldType, E fieldVal)
        this.strictInsertFill(metaObject,"createTime", LocalDateTime.class,LocalDateTime.now());// 起始版本 3.3.0(推荐使用)
    
​
    //更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) 
        log.info("start update fill ....");
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推荐)
    

六、乐观锁和悲观锁

6.1、什么是乐观锁

乐观锁:十分乐观,认为不会出现问题,无论干什么都不会去上锁,如果出现问题,就再次更新测试值

乐观锁是对于数据冲突保持一种乐观态度,操作数据时不会对操作的数据进行加锁(这使得多个任务可以并行的对数据进行操作),只有到数据提交的时候才通过一种机制来验证数据是否存在冲突(一般实现方式是通过加版本号然后进行版本号的对比方式实现);

特点:乐观锁是一种并发类型的锁,其本身不对数据进行加锁而是通过业务实现锁的功能,不对数据进行加锁就意味着允许多个请求同时访问数据,同时也省掉了对数据加锁和解锁的过程,这种方式因为节省了悲观锁加锁的操作,所以可以一定程度的的提高操作的性能,不过在并发非常高的情况下,会导致大量的请求冲突,冲突导致大部分操作无功而返而浪费资源,所以在高并发的场景下,乐观锁的性能却反而不如悲观锁。

6.2、什么是悲观锁

悲观锁:十分悲观,认为总是出现问题,无论干什么都会上锁,再去操作

悲观锁是基于一种悲观的态度类来防止一切数据冲突,它是以一种预防的姿态在修改数据之前把数据锁住,然后再对数据进行读写,在它释放锁之前任何人都不能对其数据进行操作,直到前面一个人把锁释放后下一个人数据加锁才可对数据进行加锁,然后才可以对数据进行操作,一般数据库本身锁的机制都是基于悲观锁的机制实现的;

特点:可以完全保证数据的独占性和正确性,因为每次请求都会先对数据进行加锁, 然后进行数据操作,最后再解锁,而加锁释放锁的过程会造成消耗,所以性能不高;

6.3、配置乐观锁

本文主要讲解乐观锁机制

乐观锁实现方式:

  • 取出记录时,获取当前version

  • 更新时,带上这个version

  • 执行更新时,set version = newVersion where version = oldVersion

  • 如果version不对,就更新失败

当要更新一条记录时,是希望这条记录没有被更新的

-- 乐观锁:1、先查询,获取版本号 version=1
-- A线程
update user name = "tian" ,version = version +1
where id = 2 and version = 1
-- 如果B线程抢先完成,这个时候version=2,就会导致A线程修改失败
-- B线程
update user name = "tian" ,version = version +1
where id = 2 and version = 1

测试MP的乐观锁插件

6.3.1、数据库中添加version字段

添加完成后查看是否更改完成

6.3.2、同步实体类

记得在实体类上加上@Version注解

@Version    //乐观锁version注解
private Integer version;

6.3.3、配置插件

spring xml 方式:

<bean class="com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor" id="optimisticLockerInnerInterceptor"/>
​
<bean id="mybatisPlusInterceptor" class="com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor">
    <property name="interceptors">
        <list>
            <ref bean="optimisticLockerInnerInterceptor"/>
        </list>
    </property>
</bean>

这里讲解的是springboot的注解方式

spring boot 的注解方式

@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() 
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    return interceptor;

首先创建配置类文件config,在该文件下创建配置类MyBatisPlusConfig,该类需要添加三个注解:

@Configuration  //配置类
@MapperScan("com.wen.mybatis_plus.mapper")  //扫描mapper
@EnableTransactionManagement    //自动管理事务,默认是开启的

@MapperScan()是将原先MybatisPlusApplication中的扫描换到这里的,所以MybatisPlusApplication中就不需要@MapperScan(),在该配置类里添加@MapperScan()即可

创建完MyBatisPlusConfig类并添加完注解后,就可以将上面的组件的注解方式填入进来

@Configuration  //配置类
@MapperScan("com.wen.mybatis_plus.mapper")  //扫描mapper
@EnableTransactionManagement
public class MyBatisPlusConfig 
    //注册乐观锁插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() 
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    

此时乐观锁就已经配置完成了!

6.3.4、测试乐观锁

在测试类中分别对成功与失败进行测试

测试成功:

//测试成功的乐观锁
@Test
void testOptimisticLocker_success() 
    //1.查询用户信息
    User user = userMapper.selectById(1l);
    //2.修改用户信息
    user.setName("tian");
    user.setAge(21);
    //3.执行更新操作
    userMapper.updateById(user);

结果如下:

测试失败:

模拟多线程的方式执行插队操作

@Test
void testOptimisticLocker_failure() 
    //模拟多线程实现插队效果
    //线程1
    User user = userMapper.selectById(1l);
    user.setName("tian");
    user.setAge(21);
    //线程2
    User user2 = userMapper.selectById(1l);
    user2.setName("xiaotian");
    user2.setAge(19);
    userMapper.updateById(user2);   //在这里插队
​
    userMapper.updateById(user);    //如果没有乐观锁就会覆盖插队线程的值

查看控制台输出:

从数据库看结果:

七、增删改查

7.1、查询操作

1.通过Id查询用户

//测试查询
@Test
public void testSelectById()
    User user = userMapper.selectById(1L);
    System.out.println(user);

结果:

2.批量查询

//批量查询
@Test
public void selectBatchIds()
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    users.forEach(System.out::println);

批量查询通过selectBatchIds方法,方法内放入的是集合,可以通过源码看

selectBatchIds方法源码:

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

可以看到参数是Collection也就是集合,这里使用的是Arrays集合

结果:

3.条件查询

通过自定义条件查询

//条件查询
@Test
public void selectByMap()
    HashMap<String,Object> map = new HashMap<>();
    //自定义查询
    map.put("name","小文");
    map.put("age",20);
    List<User> users = userMapper.selectByMap(map);
    users.forEach(System.out::println);

可以看出,map类的参数(字段名,参数)会被MySQLPlus自动组合成查询条件

 

7.2、分页查询

  • 原始的limit进行分页

  • pageHelper第三方插件

  • MyBatisPlus内置分页插件

支持数据库:

  • mysql,oracle,db2,h2,hsql,sqlite,postgresql,sqlserver,Phoenix,Gauss ,clickhouse,Sybase,OceanBase,Firebird,cubrid,goldilocks,csiidb

  • 达梦数据库,虚谷数据库,人大金仓数据库,南大通用(华库)数据库,南大通用数据库,神通数据库,瀚高数据库

属性介绍

属性名类型默认值描述
overflowbooleanfalse溢出总页数后是否进行处理(默认不处理)
maxLimitLong单页分页条数限制(默认无限制)
dbTypeDbType数据库类型(根据类型获取应使用的分页方言)
dialectIDialect方言实现类

建议单一数据库类型的均设置 dbType

如何使用MyBatisPlus内页插件?

1、配置拦截器组件即可

/**
 * 注册插件
 */
@Bean
public MybatisPlusInterceptor paginationInterceptor() 
​
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    // 添加分页插件
    PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor();
    // 设置请求的页面大于最大页后操作,true调回到首页,false继续请求。默认false
    pageInterceptor.setOverflow(false);
    // 单页分页条数限制,默认无限制
    pageInterceptor.setMaxLimit(500L);
    // 设置数据库类型
    pageInterceptor.setDbType(DbType.MYSQL);
​
    interceptor.addInnerInterceptor(pageInterceptor);
    return interceptor;

2、分页组件测试

//测试MybatisPlus分页插件
@Test
public void testMybatisPlus_Page()
    // 两个参数:current的值默认是1,从1开始,不是0。size是每一页的条数。
    Page<User> page = new Page<>(1, 4);
    userMapper.selectPage(page,null);
    page.getRecords().forEach(System.out::println);

结果分析:

查询第二页试试看

除此之外,Page 的方法还有很多比如:

//page的其他方法
System.out.println("当前页:" + page.getCurrent());
System.out.println("总页数:" + page.getPages());
System.out.println("记录数:" + page.getTotal());
System.out.println("是否有上一页:" + page.hasPrevious());
System.out.println("是否有下一页:" + page.hasNext());

结果:

 

7.3、删除操作

跟查询操作相似,就不详细讲解,直接上代码了

//测试删除
@Test
public void testDeleteById()
    userMapper.deleteById(4L);

​
//批量删除
@Test
public void testDeleteBatchId()
    userMapper.deleteBatchIds(Arrays.asList(1L,2L));

​
//通过map删除
@Test
public void testdeleteByMap()
    Map<String, Object> map = new HashMap<>();
    map.put("name","xiaotian");
    userMapper.deleteByMap(map);

7.4、逻辑删除

物理删除:从数据库中直接删除

逻辑删除:在数据库中没有被删除,而是通过一个变量来让它失效。 deleted=0 ==》deleted=1

管理员可以查看被删除的记录,防止数据丢失,相当于回收站。

测试:

1、在数据表中增加一个deleted字段

2、同步实体类,在实体类上加上@TableLogic 注解

@TableLogic //逻辑删除
private Integer deleted;

3、配置application.yml文件

#配置日志
mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: flag # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

4、测试

在这里直接使用之前的delete测试

//测试删除
@Test
public void testDeleteById()
    userMapper.deleteById(4L);

查看日志输出可以看到,delete的语句以经发生了更改

实质上就是update(修改)语句,将deleted字段从1修改为0

  

5、对Id为4的用户进行查询

//测试查询
@Test
public void testSelectById()
    User user = userMapper.selectById(4L);
    System.out.println(user);

查看日志输出可以看到,seletc的语句以经发生了更改

增加了deleted的判断语句,判断deleted是否为1,为1则能搜索,0则不能

 

6、小结

只对自动注入的SQL有效:

  • 插入: 不作限制

  • 查找: 追加 where 条件过滤掉已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段

  • 更新: 追加 where 条件防止更新到已删除数据,且使用 wrapper.entity 生成的 where 条件会忽略该字段

  • 删除: 转变为 更新

比如:

删除语句转化为:update user set deleted=1 where id = 1 and deleted=0

查找语句转化为:select id,name,deleted from user where deleted=0

注意事项:

  • 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。

  • 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。

八、执行SQL分析打印

可输出 SQL 语句以及其执⾏时间,建议开发测试时启⽤该功能,能快速揪出慢查询

注意:PerformanceInterceptor在3.2.0被移除了,如果想进⾏性能分析,⽤第三⽅的,官⽅这样写的“该插件 3.2.0 以上版本移除 推荐使⽤第三⽅扩展 执⾏SQL分析打印 功能”。也就是p6spy。

使用步骤:

8.1、p6spy依赖引入

Maven:

<dependency>
  <groupId>p6spy</groupId>
  <artifactId>p6spy</artifactId>
  <version>最新版本</version> <!--这里用的是>3.9.1版本-->
</dependency>

8.2、application.yml配置

spring:
  datasource:
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    url: jdbc:p6spy:h2:mem:test
    ...

注意: driver-class-name 为 p6spy 提供的驱动类 url 前缀为 jdbc:p6spy 跟着冒号为对应数据库连接地址

实际配置为:

spring:
  datasource:
    username: root
    password: 123456
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver
    url: jdbc:p6spy:mysql:///mybatis_plus?userUnicode=true&characterEncoding=utf-8

 

8.3、spy.properties配置

#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2

8.4、测试

这里使用之前的分页查询来测试一下

//测试MybatisPlus分页插件
@Test
public void testMybatisPlus_Page()
    // 两个参数:current的值默认是1,从1开始,不是0。size是每一页的条数。
    Page<User> page = new Page<>(2, 4);
    userMapper.selectPage(page,null);
    page.getRecords().forEach(System.out::println);
    //page的其他方法
    System.out.println("当前页:" + page.getCurrent());
    System.out.println("总页数:" + page.getPages());
    System.out.println("记录数:" + page.getTotal());
    System.out.println("是否有上一页:" + page.hasPrevious());
    System.out.println("是否有下一页:" + page.hasNext());

查看日志输出

 

因为在配置文件中设置了慢SQL的检查,为2s,所以这里的查询可以通过

但是只要超过了时长就会抛出异常

九、条件构造器

Wrapper,可以通过其构造复杂的SQL

注意:

1、耦合性高

2、传输wrapper相当于conroller用map接收值,后期维护极为困难

所以这里只是采取少量代码进行演示

9.1、代码演示

1、查询name、邮箱不为空且年龄大于等于20的用户

@Test
void WrapperTest()
    //查询name、邮箱不为空且年龄大于等于20的用户
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper
            .isNotNull("name")
            .isNotNull("email")
            .ge("age",12);
    userMapper.selectList(wrapper).forEach(System.out::println);

2、查询姓名为小文的用户

@Test
void WrapperTest2()
    //查询姓名为小文的用户
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.eq("name","小文");    //equals
    User user = userMapper.selectOne(wrapper); 
    System.out.println(user);

注意:

查询一个数据出现多个结果就使用List或map

3、查询年龄在19-23之间的用户

@Test
void WrapperTest3()
    //查询年龄在19-23之间的用户
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age", 19, 23);
    Long count = userMapper.selectCount(wrapper);//查询结果数
    System.out.println(count);

4、查询年龄在19-23之间的用户

@Test
void WrapperTest3()
    //查询年龄在19-23之间的用户
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.between("age", 19, 23);
    Long count = userMapper.selectCount(wrapper);//查询结果数
    System.out.println(count);

 

这里的方法取值范围是左开右闭!

5、模糊查询

@Test
void WrapperTest4()
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper
            .notLike("name","a")    //查询姓名中不包含a的用户
            .likeRight("email","t");   //左和右是代表%的位置 两边都要匹配则为%e%,这里是email以t开头的 t%
    List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
    maps.forEach(System.out::println);

 

6、联表查询

//联表查询
@Test
void WrapperTest5()
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.inSql("id","select id from user where id < 4");
    List<Object> objects = userMapper.selectObjs(wrapper);
    objects.forEach(System.out::println);

 

7、通过ID进行排序

@Test
void WrapperTest6()
    //通过ID进行排序
    QueryWrapper<User> wrapper = new QueryWrapper<>();
    wrapper.orderByAsc("id");   //通过id升序
    List<User> users = userMapper.selectList(wrapper);
    users.forEach(System.out::println);

十、代码自动生成器

MybatisPlus看官方文档即可,这里讲一个Idea插件Easy Code代码生成器

10.1、EasyCode

EasyCode是基于IntelliJ IDEA Ultimate版开发的一个代码生成插件,主要通过自定义模板(基于velocity)来生成各种你想要的代码。通常用于生成Entity、Dao、Service、Controller。如果你动手能力强还可以用于生成html、JS、php等代码。理论上来说只要是与数据有关的代码都是可以生成的。

支持的数据库类型:

  1. MySQL

  2. SQL Server

  3. Oracle

  4. PostgreSQL

  5. Sqlite

  6. Sybase

  7. Derby

  8. DB2

  9. HSQLDB

  10. H2

当然支持的数据库类型也会随着Database Tool插件的更新同步更新。

10.2、功能

  • 支持多表同时操作

  • 支持同时生成多个模板

  • 支持自定义模板

  • 支持自定义类型映射(支持正则)

  • 支持自定义附加列

  • 支持列附加属性

  • 所有配置项目支持分组模式,在不同项目(或选

    SpringBoot整合MyBatis-Plus3.1详细教程

    作者:Sans_

    juejin.im/post/5cfa6e465188254ee433bc69

    一.说明

    Mybatis-Plus是一个Mybatis框架的增强插件,根据官方描述,MP只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑.并且只需简单配置,即可快速进行 CRUD 操作,从而节省大量时间.代码生成,分页,性能分析等功能一应俱全,最新已经更新到了3.1.1版本了,3.X系列支持lambda语法,让我在写条件构造的时候少了很多的"魔法值",从代码结构上更简洁了.

    二.项目环境

    • MyBatis-Plus版本: 3.1.0

    • SpringBoot版本:2.1.5

    • JDK版本:1.8

    Maven依赖如下:

    <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </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>
            </dependency>
            <!-- mybatisPlus 核心库 -->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
                <version>3.1.0</version>
            </dependency>
            <!-- 引入阿里数据库连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.6</version>
            </dependency>
    </dependencies>

    配置如下:

    # 配置端口
    server:
      port: 8081
    spring:
      # 配置数据源
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/mp_student?useUnicode=true&characterEncoding=utf-8
        username: root
        password: root
        type: com.alibaba.druid.pool.DruidDataSource
    # mybatis-plus相关配置
    mybatis-plus:
      # xml扫描,多个目录用逗号或者分号分隔(告诉 Mapper 所对应的 XML 文件位置)
      mapper-locations: classpath:mapper/*.xml
      # 以下配置均有默认值,可以不设置
      global-config:
        db-config:
          #主键类型 AUTO:"数据库ID自增" INPUT:"用户输入ID",ID_WORKER:"全局唯一ID (数字类型唯一ID)", UUID:"全局唯一ID UUID";
          id-type: auto
          #字段策略 IGNORED:"忽略判断"  NOT_NULL:"非 NULL 判断")  NOT_EMPTY:"非空判断"
          field-strategy: NOT_EMPTY
          #数据库类型
          db-type: MYSQL
      configuration:
        # 是否开启自动驼峰命名规则映射:从数据库列名到Java属性驼峰命名的类似映射
        map-underscore-to-camel-case: true
        # 如果查询结果中包含空值的列,则 MyBatis 在映射的时候,不会映射这个字段
        call-setters-on-nulls: true
        # 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

    表结构:

    CREATE TABLE `user_info` (
      `id` bigint(11) NOT NULL AUTO_INCREMENT COMMENT ‘ID‘,
      `name` varchar(32) DEFAULT NULL COMMENT ‘姓名‘,
      `age` int(11) DEFAULT NULL COMMENT ‘年龄‘,
      `skill` varchar(32) DEFAULT NULL COMMENT ‘技能‘,
      `evaluate` varchar(64) DEFAULT NULL COMMENT ‘评价‘,
      `fraction` bigint(11) DEFAULT NULL COMMENT ‘分数‘,
      PRIMARY KEY (`id`)
    ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8mb4 COMMENT=‘学生信息表‘;

    表数据:

    INSERT INTO `user_info` VALUES (1, ‘小明‘, 20, ‘画画‘, ‘该学生在画画方面有一定天赋‘, 89);
    INSERT INTO `user_info` VALUES (2, ‘小兰‘, 19, ‘游戏‘, ‘近期该学生由于游戏的原因导致分数降低了‘, 64);
    INSERT INTO `user_info` VALUES (3, ‘张张‘, 18, ‘英语‘, ‘近期该学生参加英语比赛获得二等奖‘, 90);
    INSERT INTO `user_info` VALUES (4, ‘大黄‘, 20, ‘体育‘, ‘该学生近期由于参加篮球比赛,导致脚伤‘, 76);
    INSERT INTO `user_info` VALUES (5, ‘大白‘, 17, ‘绘画‘, ‘该学生参加美术大赛获得三等奖‘, 77);
    INSERT INTO `user_info` VALUES (7, ‘小龙‘, 18, ‘JAVA‘, ‘该学生是一个在改BUG的码农‘, 59);
    INSERT INTO `user_info` VALUES (9, ‘Sans‘, 18, ‘睡觉‘, ‘Sans是一个爱睡觉,并且身材较矮骨骼巨大的骷髅小胖子‘, 60);
    INSERT INTO `user_info` VALUES (10, ‘papyrus‘, 18, ‘JAVA‘, ‘Papyrus是一个讲话大声、个性张扬的骷髅,给人自信、有魅力的骷髅小瘦子‘, 58);
    INSERT INTO `user_info` VALUES (11, ‘删除数据1‘, 3, ‘画肖像‘, NULL, 61);
    INSERT INTO `user_info` VALUES (12, ‘删除数据2‘, 3, NULL, NULL, 61);
    INSERT INTO `user_info` VALUES (13, ‘删除数据3‘, 3, NULL, NULL, 61);
    INSERT INTO `user_info` VALUES (14, ‘删除数据4‘, 5, ‘删除‘, NULL, 10);
    INSERT INTO `user_info` VALUES (15, ‘删除数据5‘, 6, ‘删除‘, NULL, 10);

    三.编写基础类

    在启动类上添加扫描DAO的注解

    @SpringBootApplication
    @MapperScan(basePackages = "com.mp.demo.dao") //扫描DAO
    public class DemoApplication 
        public static void main(String[] args) 
            SpringApplication.run(DemoApplication.class, args);
        

    编写Config配置类

    /**
     * @Description MybatisPlus配置类
     * @Author Sans
     * @CreateTime 2019/5/26 17:20
     */
    @Configuration
    public class MybatisPlusConfig 
        /**
         * mybatis-plus SQL执行效率插件【生产环境可以关闭】
         */
        @Bean
        public PerformanceInterceptor performanceInterceptor() 
            return new PerformanceInterceptor();
        
        /**
         * 分页插件
         */
        @Bean
        public PaginationInterceptor paginationInterceptor() 
            return new PaginationInterceptor();
        

    编写Entity类

    /**
     * @Description 学生信息实体类
     * @Author Sans
     * @CreateTime 2019/5/26 21:41
     */
    @Data
    @TableName("user_info")//@TableName中的值对应着表名
    public class UserInfoEntity 

        /**
         * 主键
         * @TableId中可以决定主键的类型,不写会采取默认值,默认值可以在yml中配置
         * AUTO: 数据库ID自增
         * INPUT: 用户输入ID
         * ID_WORKER: 全局唯一ID,Long类型的主键
         * ID_WORKER_STR: 字符串全局唯一ID
         * UUID: 全局唯一ID,UUID类型的主键
         * NONE: 该类型为未设置主键类型
         */
        @TableId(type = IdType.AUTO)
        private Long id;
        /**
         * 姓名
         */
        private String name;
        /**
         * 年龄
         */
        private Integer age;
        /**
         * 技能
         */
        private String skill;
        /**
         * 评价
         */
        private String evaluate;
        /**
         * 分数
         */
        private Long fraction;

    编写Dao类

    /**
     * @Description 用户信息DAO
     * @Author Sans
     * @CreateTime 2019/6/8 16:24
     */
    public interface UserInfoDao extends BaseMapper<UserInfoEntity> 

    编写Service类

    /**
     * @Description 用户业务接口
     * @Author Sans
     * @CreateTime 2019/6/8 16:26
     */
    public interface UserInfoService extends IService<UserInfoEntity> 

    编写ServiceImpl类

    /**
     * @Description 用户业务实现
     * @Author Sans
     * @CreateTime 2019/6/8 16:26
     */
    @Service
    @Transactional
    public class UserInfoSerivceImpl extends ServiceImpl<UserInfoDao, UserInfoEntity> implements UserInfoService 

    四.MyBatis-Plus基础演示

    这里我们看到,service中我们没有写任何方法,MyBatis-Plus官方封装了许多基本CRUD的方法,可以直接使用大量节约时间,MP共通方法详见IService,ServiceImpl,BaseMapper源码,写入操作在ServiceImpl中已有事务绑定,这里我们举一些常用的方法演示.

    /**
     * @Description UserInfoController
     * @Author Sans
     * @CreateTime 2019/6/8 16:27
     */
    @RestController
    @RequestMapping("/userInfo")
    public class UserInfoController 

        @Autowired
        private UserInfoService userInfoService;

        /**
         * 根据ID获取用户信息
         * @Author Sans
         * @CreateTime 2019/6/8 16:34
         * @Param  userId  用户ID
         * @Return UserInfoEntity 用户实体
         */
        @RequestMapping("/getInfo")
        public UserInfoEntity getInfo(String userId)
            UserInfoEntity userInfoEntity = userInfoService.getById(userId);
            return userInfoEntity;
        
        /**
         * 查询全部信息
         * @Author Sans
         * @CreateTime 2019/6/8 16:35
         * @Param  userId  用户ID
         * @Return List<UserInfoEntity> 用户实体集合
         */
        @RequestMapping("/getList")
        public List<UserInfoEntity> getList()
            List<UserInfoEntity> userInfoEntityList = userInfoService.list();
            return userInfoEntityList;
        
        /**
         * 分页查询全部数据
         * @Author Sans
         * @CreateTime 2019/6/8 16:37
         * @Return IPage<UserInfoEntity> 分页数据
         */
        @RequestMapping("/getInfoListPage")
        public IPage<UserInfoEntity> getInfoListPage()
            //需要在Config配置类中配置分页插件
            IPage<UserInfoEntity> page = new Page<>();
            page.setCurrent(5); //当前页
            page.setSize(1);    //每页条数
            page = userInfoService.page(page);
            return page;
        
        /**
         * 根据指定字段查询用户信息集合
         * @Author Sans
         * @CreateTime 2019/6/8 16:39
         * @Return Collection<UserInfoEntity> 用户实体集合
         */
        @RequestMapping("/getListMap")
        public Collection<UserInfoEntity> getListMap()
            Map<String,Object> map = new HashMap<>();
            //kay是字段名 value是字段值
            map.put("age",20);
            Collection<UserInfoEntity> userInfoEntityList = userInfoService.listByMap(map);
            return userInfoEntityList;
        
        /**
         * 新增用户信息
         * @Author Sans
         * @CreateTime 2019/6/8 16:40
         */
        @RequestMapping("/saveInfo")
        public void saveInfo()
            UserInfoEntity userInfoEntity = new UserInfoEntity();
            userInfoEntity.setName("小龙");
            userInfoEntity.setSkill("JAVA");
            userInfoEntity.setAge(18);
            userInfoEntity.setFraction(59L);
            userInfoEntity.setEvaluate("该学生是一个在改BUG的码农");
            userInfoService.save(userInfoEntity);
        
        /**
         * 批量新增用户信息
         * @Author Sans
         * @CreateTime 2019/6/8 16:42
         */
        @RequestMapping("/saveInfoList")
        public void saveInfoList()
            //创建对象
            UserInfoEntity sans = new UserInfoEntity();
            sans.setName("Sans");
            sans.setSkill("睡觉");
            sans.setAge(18);
            sans.setFraction(60L);
            sans.setEvaluate("Sans是一个爱睡觉,并且身材较矮骨骼巨大的骷髅小胖子");
            UserInfoEntity papyrus = new UserInfoEntity();
            papyrus.setName("papyrus");
            papyrus.setSkill("JAVA");
            papyrus.setAge(18);
            papyrus.setFraction(58L);
            papyrus.setEvaluate("Papyrus是一个讲话大声、个性张扬的骷髅,给人自信、有魅力的骷髅小瘦子");
            //批量保存
            List<UserInfoEntity> list =new ArrayList<>();
            list.add(sans);
            list.add(papyrus);
            userInfoService.saveBatch(list);
        
        /**
         * 更新用户信息
         * @Author Sans
         * @CreateTime 2019/6/8 16:47
         */
        @RequestMapping("/updateInfo")
        public void updateInfo()
            //根据实体中的ID去更新,其他字段如果值为null则不会更新该字段,参考yml配置文件
            UserInfoEntity userInfoEntity = new UserInfoEntity();
            userInfoEntity.setId(1L);
            userInfoEntity.setAge(19);
            userInfoService.updateById(userInfoEntity);
        
        /**
         * 新增或者更新用户信息
         * @Author Sans
         * @CreateTime 2019/6/8 16:50
         */
        @RequestMapping("/saveOrUpdateInfo")
        public void saveOrUpdate()
            //传入的实体类userInfoEntity中ID为null就会新增(ID自增)
            //实体类ID值存在,如果数据库存在ID就会更新,如果不存在就会新增
            UserInfoEntity userInfoEntity = new UserInfoEntity();
            userInfoEntity.setId(1L);
            userInfoEntity.setAge(20);
            userInfoService.saveOrUpdate(userInfoEntity);
        
        /**
         * 根据ID删除用户信息
         * @Author Sans
         * @CreateTime 2019/6/8 16:52
         */
        @RequestMapping("/deleteInfo")
        public void deleteInfo(String userId)
            userInfoService.removeById(userId);
        
        /**
         * 根据ID批量删除用户信息
         * @Author Sans
         * @CreateTime 2019/6/8 16:55
         */
        @RequestMapping("/deleteInfoList")
        public void deleteInfoList()
            List<String> userIdlist = new ArrayList<>();
            userIdlist.add("12");
            userIdlist.add("13");
            userInfoService.removeByIds(userIdlist);
        
        /**
         * 根据指定字段删除用户信息
         * @Author Sans
         * @CreateTime 2019/6/8 16:57
         */
        @RequestMapping("/deleteInfoMap")
        public void deleteInfoMap()
            //kay是字段名 value是字段值
            Map<String,Object> map = new HashMap<>();
            map.put("skill","删除");
            map.put("fraction",10L);
            userInfoService.removeByMap(map);
        

    五.MyBatis-Plus的QueryWrapper条件构造器

    当查询条件复杂的时候,我们可以使用MP的条件构造器,请参考下面的QueryWrapper条件参数说明

    下面我们来举一些常见的示例

    /**
     * @Description UserInfoPlusController
     * @Author Sans
     * @CreateTime 2019/6/9 14:52
     */
    @RestController
    @RequestMapping("/userInfoPlus")
    public class UserInfoPlusController 

        @Autowired
        private UserInfoService userInfoService;

        /**
         * MP扩展演示
         * @Author Sans
         * @CreateTime 2019/6/8 16:37
         * @Return Map<String,Object> 返回数据
         */
        @RequestMapping("/getInfoListPlus")
        public Map<String,Object> getInfoListPage()
            //初始化返回类
            Map<String,Object> result = new HashMap<>();
            //查询年龄等于18岁的学生
            //等价SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE age = 18
            QueryWrapper<UserInfoEntity> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.lambda().eq(UserInfoEntity::getAge,18);
            List<UserInfoEntity> userInfoEntityList1 = userInfoService.list(queryWrapper1);
            result.put("studentAge18",userInfoEntityList1);
            //查询年龄大于5岁的学生且小于等于18岁的学生
            //等价SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE age > 5 AND age <= 18
            QueryWrapper<UserInfoEntity> queryWrapper2 = new QueryWrapper<>();
            queryWrapper2.lambda().gt(UserInfoEntity::getAge,5);
            queryWrapper2.lambda().le(UserInfoEntity::getAge,18);
            List<UserInfoEntity> userInfoEntityList2 = userInfoService.list(queryWrapper2);
            result.put("studentAge5",userInfoEntityList2);
            //模糊查询技能字段带有"画"的数据,并按照年龄降序
            //等价SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE skill LIKE ‘%画%‘ ORDER BY age DESC
            QueryWrapper<UserInfoEntity> queryWrapper3 = new QueryWrapper<>();
            queryWrapper3.lambda().like(UserInfoEntity::getSkill,"画");
            queryWrapper3.lambda().orderByDesc(UserInfoEntity::getAge);
            List<UserInfoEntity> userInfoEntityList3 = userInfoService.list(queryWrapper3);
            result.put("studentAgeSkill",userInfoEntityList3);
            //模糊查询名字带有"小"或者年龄大于18的学生
            //等价SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE name LIKE ‘%小%‘ OR age > 18
            QueryWrapper<UserInfoEntity> queryWrapper4 = new QueryWrapper<>();
            queryWrapper4.lambda().like(UserInfoEntity::getName,"小");
            queryWrapper4.lambda().or().gt(UserInfoEntity::getAge,18);
            List<UserInfoEntity> userInfoEntityList4 = userInfoService.list(queryWrapper4);
            result.put("studentOr",userInfoEntityList4);
            //查询评价不为null的学生,并且分页
            //等价SQL: SELECT id,name,age,skill,evaluate,fraction FROM user_info WHERE evaluate IS NOT NULL LIMIT 0,5
            IPage<UserInfoEntity> page = new Page<>();
            page.setCurrent(1);
            page.setSize(5);
            QueryWrapper<UserInfoEntity> queryWrapper5 = new QueryWrapper<>();
            queryWrapper5.lambda().isNotNull(UserInfoEntity::getEvaluate);
            page = userInfoService.page(page,queryWrapper5);
            result.put("studentPage",page);
            return result;
        

    六.自定义SQL

    引入Mybatis-Plus不会对项目现有的 Mybatis 构架产生任何影响,而且Mybatis-Plus支持所有 Mybatis 原生的特性,这也是我喜欢使用它的原因之一,由于某些业务复杂,我们可能要自己去写一些比较复杂的SQL语句,我们举一个简单的例子来演示自定义SQL.

    示例:查询大于设置分数的学生(分数为动态输入,且有分页)

    编写Mapper.xml文件

    <mapper namespace="com.mp.demo.dao.UserInfoDao">
        <!-- Sans 2019/6/9 14:35 -->
        <select id="selectUserInfoByGtFraction" resultType="com.mp.demo.entity.UserInfoEntity" parameterType="long">
        SELECT * FROM user_info WHERE fraction > #fraction
        </select>
    </mapper>

    在DAO中加入方法

        /**
         * 查询大于该分数的学生
         * @Author Sans
         * @CreateTime 2019/6/9 14:28
         * @Param  page  分页参数
         * @Param  fraction  分数
         * @Return IPage<UserInfoEntity> 分页数据
         */
        IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page, Long fraction);

    在service加入方法

        /**
         * 查询大于该分数的学生
         * @Author Sans
         * @CreateTime 2019/6/9 14:27
         * @Param  page  分页参数
         * @Param  fraction  分数
         * @Return IPage<UserInfoEntity> 分页数据
         */
        IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page,Long fraction);

    在serviceImpl加入方法

        /**
         * 查询大于该分数的学生
         * @Author Sans
         * @CreateTime 2019/6/9 14:27
         * @Param  page  分页参数
         * @Param  fraction  分数
         * @Return IPage<UserInfoEntity> 分页数据
         */
        @Override
        public IPage<UserInfoEntity> selectUserInfoByGtFraction(IPage<UserInfoEntity> page, Long fraction) 
            return this.baseMapper.selectUserInfoByGtFraction(page,fraction);
        

    在Controller中测试

        /**
         * MP自定义SQL
         * @Author Sans
         * @CreateTime 2019/6/9 14:37
         * @Return IPage<UserInfoEntity> 分页数据
         */
        @RequestMapping("/getInfoListSQL")
        public IPage<UserInfoEntity> getInfoListSQL()
            //查询大于60分以上的学生,并且分页
            IPage<UserInfoEntity> page = new Page<>();
            page.setCurrent(1);
            page.setSize(5);
            page = userInfoService.selectUserInfoByGtFraction(page,60L);
            return page;
        

    七.项目源码

    项目源码:

    https://gitee.com/liselotte/spring-boot-mp-demo

    个人确实很喜欢用MyBatis-Plus,不仅节约时间,代码也简洁干净,它给了我那时候从SSM到SpringBoot过度的那种感觉

    嗯,这玩意真香~

    推荐阅读(点击即可跳转阅读)

     

    1. SpringBoot内容聚合

    2. 面试题内容聚合

    3. 设计模式内容聚合

    4. Mybatis内容聚合

    5. 多线程内容聚合

     

    以上是关于MyBatis Plus详细教程的主要内容,如果未能解决你的问题,请参考以下文章

    MyBatis Plus详细教程

    SpringBoot整合MyBatis-Plus3.1详细教程

    好程序员Java教程分享MyBatis Plus介绍

    Mybatis-Plus详细使用

    瑞吉外卖项目 基于spring Boot+mybatis-plus开发 超详细笔记,有源码链接

    Mybatis-Plus 实战教程