mybatis-plus学习及使用
什么是Mybatis-Plus
MyBatis-Plus 是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。
Mybatis-Plus的特性
- 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
- 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作
官方网站
快速起步
版本说明
本文档使用的是MyBatis-Plus v3.4.2
准备数据库
1、创建数据库 mybatis-plus
2、导入如下脚本
DROP TABLE IF EXISTS USER;
CREATE TABLE USER
(
    id BIGINT(20) NOT NULL AUTO_INCREMENT 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)
) DEFAULT CHARSET=UTF8;
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');创建SpringBoot项目





导入依赖
修改 pom.xml 文件
<!-- MySql数据库相关依赖 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency><!-- MyBatis-Plus相关依赖 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>配置数据源
1、修改配置文件类型
将 src/main/resources/application.properties 更改为 src/main/resources/application.yml
2、添加如下配置
server:
  port: 8080
spring:
  datasource:
    username: root
    password: ok
    url: jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
    driver-class-name: com.mysql.cj.jdbc.Driver配置启动类
修改 com.yacon.mybatisplus.MybatisPlusApplication 类
package com.yacon.mybatisplus;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
 @MapperScan("com.yacon.mybatisplus.mapper")
public class MybatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusApplication.class, args);
    }
}创建POJO类
创建 com.yacon.mybatisplus.pojo.User 类
package com.yacon.mybatisplus.pojo;
import lombok.Data;
@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;
}创建Mapper类
创建 com.yacon.mybatisplus.mapper.UserMapper 接口
package com.yacon.mybatisplus.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yacon.mybatisplus.pojo.User;
public interface UserMapper extends BaseMapper<User> { }编写测试方法
1、修改 src/test/java/com/yacon/mybatisplus/MybatisPlusApplicationTests.java文件
package com.yacon.mybatisplus;
import com.yacon.mybatisplus.mapper.UserMapper;
import com.yacon.mybatisplus.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.util.List;
@SpringBootTest
class MybatisPlusApplicationTests {
    @Resource
    private UserMapper userMapper;
    /**
     * 查询所有用户列表
     */
    @Test
    public void testSelect(){
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }
}2、运行测试

日志输出
1、修改 src/main/resources/application.yml 配置文件,添加日志配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl2、运行测试

基础CRUD
SELECT
根据ID查询
1、添加测试方法
/**
 * 查询用户信息
 */
@Test
public void testGetUserById(){
    User user = userMapper.selectById(5);
    if(null == user) {
        System.out.println("查询失败");
        return;
    }
    System.out.println(user.getId());
    System.out.println(user.getName());
    System.out.println(user.getAge());
    System.out.println(user.getEmail());
}2、运行测试

查询总条目数
1、编写测试方法
/**
 * 查询总条目数
 */
@Test
public void testGetUserCount(){
    Integer count = userMapper.selectCount(null);
    System.out.println(count);
}2、运行测试

条件查询
1、编写测试方法
/**
 * 查询年龄大于20岁的用户
 */
@Test
public void testWhere(){
    QueryWrapper queryWrapper = new QueryWrapper();
    queryWrapper.gt("age",20);
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}2、运行测试

模糊查询
1、编写测试方法
/**
 * 查询姓名包含 a 的用户
 */
@Test
public void testLike(){
    QueryWrapper queryWrapper = new QueryWrapper();
    queryWrapper.like("name",'a');
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}2、运行测试

排序查询
1、添加测试方法
/**
 * 查询用户列表,并按年龄逆序
 */
@Test
public void testOrder() {
    QueryWrapper queryWrapper = new QueryWrapper();
    queryWrapper.orderByDesc("age");
    List<User> users = userMapper.selectList(queryWrapper);
    users.forEach(System.out::println);
}2、运行测试

INSERT
配置主键生成策略
1、确保数据表的主键列为自增列

2、修改 com.yacon.mybatisplus.pojo.User 类
@Data
public class User {
   @TableId(type= IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}编写测试方法
1、添加测试方法
/**
 * 插入用户
 */
@Test
public void testInsert(){
    User user = new User();
    user.setName("张三");
    user.setAge(20);
    user.setEmail("zhangsan@mail.com");
    int result = userMapper.insert(user);
    System.out.println(result > 0 ? "插入成功" : "插入失败");
    System.out.println("ID="+user.getId());
}2、运行测试


UPDATE
1、添加测试方法
/**
 * 更新用户
 */
@Test
public void testUpdate(){
    User user = new User();
    user.setId(6L);
    user.setName("zhangsan");
    int result = userMapper.updateById(user);
    System.out.println(result > 0 ? "修改成功" : "修改失败");
}2、运行测试


DELETE
1、添加测试方法
/**
 * 删除用户
 */
@Test
public void testDelete(){
    int result = userMapper.deleteById(6);
    System.out.println(result > 0 ? "删除成功" : "删除失败");
}2、运行测试

高级扩展
逻辑删除
逻辑删除 是指,在删除表中的某条数据时并不是真正的删除,而是更改某个表字段的值来表示该条数据已被删除
修改数据表
给 User 添加字段 deleted,并设置默认值为 0
ALTER TABLE `mybatis_plus`.`user` ADD COLUMN `deleted` INT(1) DEFAULT 0 NOT NULL AFTER `email`;修改实体类
修改 com.yacon.mybatisplus.pojo.User 类
@Data
public class User {
    @TableId(type= IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
   @TableLogic
   private Integer deleted;
}添加配置
修改 src/main/resources/application.yml 文件
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
 global-config:
   db-config:
     logic-delete-field: deleted # 全局逻辑删除的实体字段名
     logic-delete-value: 1 # 逻辑已删除的值
     logic-not-delete-value: 0 # 逻辑未删除的值运行测试
1、运行 删除用户 测试方法


2、运行 查询所有用户列表 测试方法

自动填充字段
修改数据表
给 user 表添加两个字段 gmt-create 和 gmt-modified
ALTER TABLE `mybatis_plus`.`user`   
  ADD COLUMN `gmt_create` DATETIME NULL  COMMENT '创建时间' AFTER `deleted`,
  ADD COLUMN `gmt_modified` DATETIME NULL  COMMENT '更新时间' AFTER `gmt_create`;
修改实体类
修改 com.yacon.mybatisplus.pojo.User 类
@Data
public class User {
    @TableId(type= IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @TableLogic
    private Integer deleted;
   @TableField(fill = FieldFill.INSERT)
   private Date gmtCreate;
   @TableField(fill = FieldFill.INSERT_UPDATE)
   private Date gmtModified;
}编写填充处理器
创建 com.yacon.mybatisplus.handle.MyMetaObjectHandler 类
package com.yacon.mybatisplus.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("gmtCreate",new Date(), metaObject);
        this.setFieldValByName("gmtModified",new Date(), metaObject);
    }
    @Override
    public void updateFill(MetaObject metaObject) {
        this.setFieldValByName("gmtModified",new Date(), metaObject);
    }
}运行测试
1、运行 插入用户 测试方法


2、运行 更新用户 测试方法


常用插件
乐观锁
在高并发的情况下,可能存在多个用户同时修改一条数据的情况,为了让某一用户在修改数据时不被被人更新,这时就需要用乐观锁将数据进行锁定
乐观锁实现方式
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
修改数据表
给 user 表添加 version 字段 b
ALTER TABLE `mybatis_plus`.`user`   
  ADD COLUMN `version` INT DEFAULT 1  NULL  COMMENT '乐观锁' AFTER `email`;
修改实体类
修改 com.yacon.mybatisplus.pojo.User 类
@Data
public class User {
    @TableId(type= IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    @TableLogic
    private Integer deleted;
    @TableField(fill = FieldFill.INSERT)
    private Date gmtCreate;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmtModified;
   @Version
   private Integer version;
}注册插件
1、创建 com.yacon.mybatisplus.config.MyBatisPlusConfig 类
package com.yacon.mybatisplus.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@EnableTransactionManagement
@MapperScan("com.yacon.mybatisplus.mapper")
public class MyBatisPlusConfig {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 注册乐观锁插件
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }
}
2、修改 om.yacon.mybatisplus.MybatisPlusApplication 启动类
@SpringBootApplication
 @MapperScan("com.yacon.mybatisplus.mapper")
public class MybatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MybatisPlusApplication.class, args);
    }
}运行测试
1、添加测试方法
/**
 * 乐观锁测试
 */
@Test
public void testLocker() {
    // 模拟线程1
    User user1 = userMapper.selectById(7L);
    user1.setName("张三");
    // 模拟线程2插队
    User user2 = userMapper.selectById(7L);
    user2.setName("李四");
    userMapper.updateById(user2);
    userMapper.updateById(user1);
}2、运行测试


分页查询
注册分页插件
修改 com.yacon.mybatisplus.config.MyBatisPlusConfig 类
注意注册插件的顺序,要先注册 分页插件,再注册 乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
   // 注册分页插件
   interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    // 注册乐观锁插件
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
    return interceptor;
}添加测试方法
修改 com.yacon.mybatisplus.MybatisPlusApplicationTests 测试类
/**
 * 分页查询
 */
@Test
public void testPage(){
    long current = 1; // 当前页码
    long size = 2; // 每页显示条目数
    Page<User> page = new Page<>(current,size);
    userMapper.selectPage(page, null);
    List<User> users = page.getRecords(); // 获取数据列表
    users.forEach(System.out::println);
}运行测试

性能分析
SQL性能校验
注册插件
修改 com.yacon.mybatisplus.config.MyBatisPlusConfig 类
性能分析插件 要放在 分页插件 和 乐观锁插件 之后
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
    MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
    // 注册分页插件
    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    // 注册乐观锁插件
    interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
   // 注册性能分析插件
   interceptor.addInnerInterceptor(new IllegalSQLInnerInterceptor());
    return interceptor;
}运行测试
1、运行 查询所有用户列表 测试方法
由于我们开启了 逻辑删除,所以在查询时需要使用 deleted 为查询条件进行查询,但我们没有给 deleted 字段添加索引,所以这里报了一个 未使用索引的错误

2、修改数据库,给 deleted 字段添加索引
注意:添加组合索引时,deleted 一定要放在第一个,否则,使用单个deleted 作为条件查询时无法触发索引
ALTER TABLE `mybatis_plus`.`user`
  ADD  UNIQUE INDEX `id_deleted_unique` (`deleted`, `id`);
3、重新运行 查询所有用户列表 测试方法

SQL性能分析
该功能有性能损耗,不建议生产环境使用
添加依赖
修改 pom.xml
<dependency>
    <groupId>p6spy</groupId>
    <artifactId>p6spy</artifactId>
    <version>3.9.1</version>
</dependency>修改数据源
修改 src/main/resources/application.yml
spring:
  datasource:
    username: root
    password: ok
   url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
   driver-class-name: com.p6spy.engine.spy.P6SpyDriver
   url: jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
   driver-class-name: com.mysql.cj.jdbc.Driver配置p6spy
创建 src/main/resources/spy.properties
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,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
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2运行测试
执行 查询用户信息 测试方法

代码生成器
创建SpringBoot项目
新建一个SpringBoot项目
导入依赖
修改 pom.xml 文件
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.0.5</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.2</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.9.2</version>
</dependency>编写代码生成器
创建 MyBatisPlusAutoCode 类
package com.yacon.mybatisplus;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
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.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.ArrayList;
/**
 * 代码生成器
 */
public class MyBatisPlusAutoCode {
    public static void main(String[] args) {
        AutoGenerator mpg = new AutoGenerator();
        /* 全局配置 */
        GlobalConfig gc = new GlobalConfig();
        //生成文件的输出目录
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        // 是否打开输出目录
        gc.setOpen(false);
        // 是否覆盖已有文件
        gc.setFileOverride(true);
        // 开发人员
        gc.setAuthor("Yacon");
        // 是否生成swagger2注解
        gc.setSwagger2(true);
        // 时间类型对应策略
        gc.setDateType(DateType.TIME_PACK);
        // mapper 命名方式
        gc.setMapperName("%sDao");
        // Mapper xml 命名方式
        gc.setXmlName("%sDao");
        // service 命名方式
        gc.setServiceName("%sService");
        // service impl 命名方式
        gc.setServiceImplName("%sServiceImpl");
        // controller 命名方式
        gc.setControllerName("%sController");
        // 指定生成的主键的ID类型
        gc.setIdType(IdType.AUTO);
        // 设置全局配置
        mpg.setGlobalConfig(gc);
        /* 数据源配置 */
        DataSourceConfig dsc = new DataSourceConfig();
        // 数据库类型
        dsc.setDbType(DbType.MYSQL);
        // 驱动连接的URL
        dsc.setUrl("jdbc:mysql://localhost:3306/cvs_db?useUnicode=true&useSSL=false&characterEncoding=utf8&serverTimezone=GMT%2B8");
        // 驱动名称
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        // 数据库账号
        dsc.setUsername("root");
        // 数据库密码
        dsc.setPassword("ok");
        // 设置数据库配置
        mpg.setDataSource(dsc);
        /* 包配置 */
        PackageConfig pc = new PackageConfig();
        // 父包模块名
        pc.setModuleName("api");
        // 父包名
        pc.setParent("com.yacon.mybatisplus");
        // Entity包名
        pc.setEntity("pojo");
        // Service包名
        pc.setService("service");
        // Service Impl包名
        pc.setServiceImpl("service");
        // Mapper包名
        pc.setMapper("dao");
        // Mapper XML包名
        pc.setXml("dao");
        // Controller包名
        pc.setController("controller");
        // 设置包配置
        mpg.setPackageInfo(pc);
        /* 策略配置 */
        StrategyConfig strategy = new StrategyConfig();
        // 需要包含的表名
        strategy.setInclude("t_address","t_storage_record","t_supplier","t_sys_role","t_sys_user");
        // 表前缀
        strategy.setTablePrefix("t_");
        // 数据库表映射到实体的命名策略
        strategy.setNaming(NamingStrategy.underline_to_camel);
        // 数据库表字段映射到实体的命名策略
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        // 是否为lombok模型
        strategy.setEntityLombokModel(true);
        // Boolean类型字段是否移除is前缀
        strategy.setEntityBooleanColumnRemoveIsPrefix(true);
        // 生成 @RestController 控制器
        strategy.setRestControllerStyle(true);
        // 驼峰转连字符
        strategy.setControllerMappingHyphenStyle(true);
        // 乐观锁属性名称
        strategy.setVersionFieldName("version");
        // 逻辑删除属性名称
        strategy.setLogicDeleteFieldName("deleted");
        // 表填充字段
        TableFill gmtCreate = new TableFill("gmt_create", FieldFill.INSERT);
        TableFill gmtModified = new TableFill("gmt_modified", FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(gmtCreate);
        tableFills.add(gmtModified);
        strategy.setTableFillList(tableFills);
        // 设置策略配置
        mpg.setStrategy(strategy);
        // 执行
        mpg.execute();
    }
}
运行代码生成器

 
                    
                

 
 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号