JAVASpring

SpringBoot MyBatis-Plus

一、了解mybatisplus


MyBatis-Plus (简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

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

二、支持数据库


任何能使用 MyBatis 进行 CRUD, 并且支持标准 SQL 的数据库。

  • MySQL,Oracle,DB2,H2,HSQL,SQLite,PostgreSQL,SQLServer,Phoenix,Gauss ,ClickHouse,Sybase,OceanBase,Firebird,Cubrid,Goldilocks,csiidb
  • 达梦数据库,虚谷数据库

三、框架结构


四、springboot整合MybatisPlus快速入门


1.手动添加MyBatisPlus依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter

</artifactId>
    <version>3.4.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.16</version>
</dependency>
<!--mysql-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

2.制作实体类与表结构(类名与表名对应,属性名与字段名对应)

create database if not exists mybatisplus_db character set utf8;
use mybatisplus_db;
CREATE TABLE user (
            id bigint(20) primary key auto_increment,
            name varchar(32) not null,
            password  varchar(32) not null,
            age int(3) not null ,
            tel varchar(32) not null
);
insert into user values(null,'tom','123456',12,'12345678910');
insert into user values(null,'jack','123456',8,'12345678910');
insert into user values(null,'jerry','123456',15,'12345678910');
insert into user values(null,'tom','123456',9,'12345678910');
insert into user values(null,'snake','123456',28,'12345678910');
insert into user values(null,'张益达','123456',22,'12345678910');
insert into user values(null,'张大炮','123456',16,'12345678910');

public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;
    //自行添加getter、setter、toString()等方法
}

3.设置Jdbc参数(application.yml)

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatisplus_db?serverTimezone=UTC
    username: root
    password: 1234

4.定义数据接口,继承BaseMapper

使用代码生成器生成的 mapper 接口中,其继承了 BaseMapper 接口。而 BaseMapper 接口中封装了一系列 CRUD 常用操作,可以直接使用,而不用自定义 xml 与 sql 语句进行 CRUD 操作(当然根据实际开发需要,自定义 sql 还是有必要的)。

package com.itheima.dao;
​
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.Mapper;
​
@Mapper
public interface UserDao extends BaseMapper<User> {
}
​

5.测试类中注入dao接口,测试功能

作者:黑马程序员Java
链接:https://www.zhihu.com/question/314745062/answer/2744432305
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

package com.itheima;
​
import com.itheima.dao.UserDao;
import com.itheima.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
​
import java.util.List;
​
@SpringBootTest
public class Mybatisplus01QuickstartApplicationTests {
​
    @Autowired
    private UserDao userDao;
​
    @Test
    void testGetAll() {
        List<User> userList = userDao.selectList(null);
        System.out.println(userList);
    }
}

6.执行结果

通过以上简单操作,就能对 表进行 CRUD 操作,不需要去编写 xml 文件。

五、优点


  • (1)无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。
  • (2)损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作。
  • (3)强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求。
  • (4)支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错。
  • (5)支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 – Sequence),可自由配置,完美解决主键问题。
  • (6)支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作。
  • (7)支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )。
  • (8)内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用。
  • (9)内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询。
  • (10)分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库。
  • (11)内置性能分析插件:可输出 SQL 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询。
  • (12)内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作。

六.Mybatis-Plus 常用操作

6.1 配置日志


【参考地址(两种方式配置日志)】     
 https://blog.csdn.net/dfBeautifulLive/article/details/100700365 

想要查看执行的 sql 语句,可以在 yml 文件中添加配置信息,如下。

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

如下图所示:执行时会打印出 sql 语句。

6.2 代码生成器


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

与 mybatis 中的 mybatis-generator-core 类似。

添加依赖

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.3.1.tmp</version>
</dependency>
<!-- 添加 模板引擎 依赖 -->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.2</version>
</dependency>

代码分析

Step1:创建一个 代码生成器。用于生成代码。

// Step1:代码生成器
AutoGenerator mpg = new AutoGenerator();

Step2:配置全局信息。指定代码输出路径,以及包名、作者等信息。此处按需添加,projectPath 需要修改,setAuthor 需要修改。

// Step2:全局配置
GlobalConfig gc = new GlobalConfig();
// 填写代码生成的目录(需要修改)
String projectPath = "E:\\myProject\\test\\test_mybatis_plus";
// 拼接出代码最终输出的目录
gc.setOutputDir(projectPath + "/src/main/java");
// 配置开发者信息(可选)(需要修改)
gc.setAuthor("lyh");
// 配置是否打开目录,false 为不打开(可选)
gc.setOpen(false);
// 实体属性 Swagger2 注解,添加 Swagger 依赖,开启 Swagger2 模式(可选)
//gc.setSwagger2(true);
// 重新生成文件时是否覆盖,false 表示不覆盖(可选)
gc.setFileOverride(false);
// 配置主键生成策略,此处为 ASSIGN_ID(可选)
gc.setIdType(IdType.ASSIGN_ID);
// 配置日期类型,此处为 ONLY_DATE(可选)
gc.setDateType(DateType.ONLY_DATE);
// 默认生成的 service 会有 I 前缀
gc.setServiceName("%sService");
mpg.setGlobalConfig(gc);

Step3:配置数据源信息。用于指定 需要生成代码的 数据仓库、数据表。setUrl、setDriverName、setUsername、setPassword 均需修改。

// Step3:数据源配置(需要修改)
DataSourceConfig dsc = new DataSourceConfig();
// 配置数据库 url 地址
dsc.setUrl("jdbc:mysql://localhost:3306/testMyBatisPlus?useUnicode=true&characterEncoding=utf8");
// dsc.setSchemaName("testMyBatisPlus"); // 可以直接在 url 中指定数据库名
// 配置数据库驱动
dsc.setDriverName("com.mysql.cj.jdbc.Driver");
// 配置数据库连接用户名
dsc.setUsername("root");
// 配置数据库连接密码
dsc.setPassword("123456");
mpg.setDataSource(dsc);

Step4:配置包信息。setParent、setModuleName 均需修改。其余按需求修改.

// Step:4:包配置
PackageConfig pc = new PackageConfig();
// 配置父包名(需要修改)
pc.setParent("com.lyh.test");
// 配置模块名(需要修改)
pc.setModuleName("test_mybatis_plus");
// 配置 entity 包名
pc.setEntity("entity");
// 配置 mapper 包名
pc.setMapper("mapper");
// 配置 service 包名
pc.setService("service");
// 配置 controller 包名
pc.setController("controller");
mpg.setPackageInfo(pc);

Step5:配置数据表映射信息。setInclude 需要修改,其余按实际开发修改。

// Step5:策略配置(数据库表配置)
StrategyConfig strategy = new StrategyConfig();
// 指定表名(可以同时操作多个表,使用 , 隔开)(需要修改)
strategy.setInclude("test_mybatis_plus_user");
// 配置数据表与实体类名之间映射的策略
strategy.setNaming(NamingStrategy.underline_to_camel);
// 配置数据表的字段与实体类的属性名之间映射的策略
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
// 配置 lombok 模式
strategy.setEntityLombokModel(true);
// 配置 rest 风格的控制器(@RestController)
strategy.setRestControllerStyle(true);
// 配置驼峰转连字符
strategy.setControllerMappingHyphenStyle(true);
// 配置表前缀,生成实体时去除表前缀
// 此处的表名为 test_mybatis_plus_user,模块名为 test_mybatis_plus,去除前缀后剩下为 user。
strategy.setTablePrefix(pc.getModuleName() + "_");
mpg.setStrategy(strategy);

Step6:执行代码生成操作。

// Step6:执行代码生成操作
mpg.execute();

完整配置如下:

package com.lyh.test.test_mybatis_plus;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.jupiter.api.Test;

public class TestAutoGenerate {
    @Test
    public void autoGenerate() {
        // Step1:代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // Step2:全局配置
        GlobalConfig gc = new GlobalConfig();
        // 填写代码生成的目录(需要修改)
        String projectPath = "E:\\myProject\\test\\test_mybatis_plus";
        // 拼接出代码最终输出的目录
        gc.setOutputDir(projectPath + "/src/main/java");
        // 配置开发者信息(可选)(需要修改)
        gc.setAuthor("lyh");
        // 配置是否打开目录,false 为不打开(可选)
        gc.setOpen(false);
        // 实体属性 Swagger2 注解,添加 Swagger 依赖,开启 Swagger2 模式(可选)
        //gc.setSwagger2(true);
        // 重新生成文件时是否覆盖,false 表示不覆盖(可选)
        gc.setFileOverride(false);
        // 配置主键生成策略,此处为 ASSIGN_ID(可选)
        gc.setIdType(IdType.ASSIGN_ID);
        // 配置日期类型,此处为 ONLY_DATE(可选)
        gc.setDateType(DateType.ONLY_DATE);
        // 默认生成的 service 会有 I 前缀
        gc.setServiceName("%sService");
        mpg.setGlobalConfig(gc);

        // Step3:数据源配置(需要修改)
        DataSourceConfig dsc = new DataSourceConfig();
        // 配置数据库 url 地址
        dsc.setUrl("jdbc:mysql://localhost:3306/testMyBatisPlus?useUnicode=true&characterEncoding=utf8");
        // dsc.setSchemaName("testMyBatisPlus"); // 可以直接在 url 中指定数据库名
        // 配置数据库驱动
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        // 配置数据库连接用户名
        dsc.setUsername("root");
        // 配置数据库连接密码
        dsc.setPassword("123456");
        mpg.setDataSource(dsc);

        // Step:4:包配置
        PackageConfig pc = new PackageConfig();
        // 配置父包名(需要修改)
        pc.setParent("com.lyh.test");
        // 配置模块名(需要修改)
        pc.setModuleName("test_mybatis_plus");
        // 配置 entity 包名
        pc.setEntity("entity");
        // 配置 mapper 包名
        pc.setMapper("mapper");
        // 配置 service 包名
        pc.setService("service");
        // 配置 controller 包名
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        // Step5:策略配置(数据库表配置)
        StrategyConfig strategy = new StrategyConfig();
        // 指定表名(可以同时操作多个表,使用 , 隔开)(需要修改)
        strategy.setInclude("test_mybatis_plus_user");
        // 配置数据表与实体类名之间映射的策略
        strategy.setNaming(NamingStrategy.underline_to_camel);
        // 配置数据表的字段与实体类的属性名之间映射的策略
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        // 配置 lombok 模式
        strategy.setEntityLombokModel(true);
        // 配置 rest 风格的控制器(@RestController)
        strategy.setRestControllerStyle(true);
        // 配置驼峰转连字符
        strategy.setControllerMappingHyphenStyle(true);
        // 配置表前缀,生成实体时去除表前缀
        // 此处的表名为 test_mybatis_plus_user,模块名为 test_mybatis_plus,去除前缀后剩下为 user。
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);

        // Step6:执行代码生成操作
        mpg.execute();
    }
}

6.3 分页插件的使用


与 mybatis 的插件 pagehelper 用法类似。通过简单的配置即可使用。

Step1:配置分页插件。编写一个 配置类,内部使用 @Bean 注解将 PaginationInterceptor 交给 Spring 容器管理。

package com.lyh.test.test_mybatis_plus.config;

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 自定义一个配置类,mapper 扫描也可在此写上
 */
@Configuration
@MapperScan("com.lyh.test.test_mybatis_plus.mapper")
public class Myconfig {
    /**
     * 分页插件
     * @return 分页插件的实例
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

Step2:编写分页代码。直接 new 一个 Page 对象,对象需要传递两个参数(当前页,每页显示的条数)。调用 mybatis-plus 提供的分页查询方法,其会将 分页查询的数据封装到 Page 对象中。

@Test
public void testPage() {
    // Step1:创建一个 Page 对象
    Page<User> page = new Page<>();
    // Page<User> page = new Page<>(2, 5);
    // Step2:调用 mybatis-plus 提供的分页查询方法
    userService.page(page, null);
    // Step3:获取分页数据
    System.out.println(page.getCurrent()); // 获取当前页
    System.out.println(page.getTotal()); // 获取总记录数
    System.out.println(page.getSize()); // 获取每页的条数
    System.out.println(page.getRecords()); // 获取每页数据的集合
    System.out.println(page.getPages()); // 获取总页数
    System.out.println(page.hasNext()); // 是否存在下一页
    System.out.println(page.hasPrevious()); // 是否存在上一页
}

6.4 自动填充数据功能


添加、修改数据时,每次都会使用相同的方式进行填充。比如 数据的创建时间、修改时间等。

Mybatis-plus 支持自动填充这些字段的数据。给之前的数据表新增两个字段:创建时间、修改时间。

CREATE TABLE test_mybatis_plus_user
(
    id BIGINT 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 '邮箱',
    create_time timestamp NULL DEFAULT NULL COMMENT '创建时间',
    update_time timestamp NULL DEFAULT NULL COMMENT '最后修改时间', 
    PRIMARY KEY (id)
);

并使用 代码生成器生成代码。

未使用自动填充时,每次添加、修改数据都可以手动对其进行添加。

@SpringBootTest
class TestMybatisPlusApplicationTests {

    @Autowired
    private UserService userService;

    @Test
    public void testUpdate() {
        User user = new User();
        user.setName("tom").setAge(20).setEmail("tom@163.com");
        // 手动添加数据
        user.setCreateTime(new Date()).setUpdateTime(new Date());
        if (userService.save(user)) {
            userService.list().forEach(System.out::println);
        } else {
            System.out.println("添加数据失败");
        }
    }
}

使用自动填充功能。

Step1:使用 @TableField 注解,标注需要进行填充的字段。

/**
 * 创建时间
 */
@TableField(fill = FieldFill.INSERT)
private Date createTime;

/**
 * 最后修改时间
 */
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

Step2:自定义一个类,实现 MetaObjectHandler 接口,并重写方法。添加 @Component 注解,交给 Spring 去管理。

package com.lyh.test.test_mybatis_plus.handler;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
        this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
    }
}

Step3:简单测试一下。

@Test
public void testAutoFill() {
    User user = new User();
    user.setName("tom").setAge(20).setEmail("tom@163.com");
    if (userService.save(user)) {
        userService.list().forEach(System.out::println);
    } else {
        System.out.println("添加数据失败");
    }
}

6.5 逻辑删除


删除数据,可以通过物理删除,也可以通过逻辑删除。

物理删除指的是直接将数据从数据库中删除,不保留。

逻辑删除指的是修改数据的某个字段,使其表示为已删除状态,而非删除数据,保留该数据在数据库中,但是查询时不显示该数据(查询时过滤掉该数据)。

给数据表增加一个字段:delete_flag,用于表示该数据是否被逻辑删除。

CREATE TABLE test_mybatis_plus_user
(
    id BIGINT 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 '邮箱',
    create_time timestamp NULL DEFAULT NULL COMMENT '创建时间',
    update_time timestamp NULL DEFAULT NULL COMMENT '最后修改时间', 
    delete_flag tinyint(1) NULL DEFAULT NULL COMMENT '逻辑删除(0 未删除、1 删除)',
    PRIMARY KEY (id)
);

使用逻辑删除。可以定义一个自动填充规则,初始值为 0。0 表示未删除, 1 表示删除。

/**
 * 逻辑删除(0 未删除、1 删除)
 */
@TableLogic(value = "0", delval = "1")
@TableField(fill = FieldFill.INSERT)
private Integer deleteFlag;


@Override
public void insertFill(MetaObject metaObject) {
    this.strictInsertFill(metaObject, "deleteFlag", Integer.class, 0);
}

简单测试:使用 mybatis-plus 封装好的方法时,会自动添加逻辑删除的功能。若是自定义的 sql 语句,需要手动添加逻辑。

@Test
public void testDelete() {
    if (userService.removeById(1258924257048547329L)) {
        System.out.println("删除数据成功");
        userService.list().forEach(System.out::println);
    } else {
        System.out.println("删除数据失败");
    }
}

现有数据

执行 testDelete 进行逻辑删除。

若去除 TableLogic 注解,再执行 testDelete 时进行物理删除,直接删除这条数据。