mybatis-plus知识总结

MyBatis-Plus是一款增强型ORM框架,提供无侵入、高性能的CRUD操作,支持Lambda表达式和自动生成主键,简化了数据库操作并支持ActiveRecord模式。本文介绍了基础使用和关键特性,如自动填充、分页插件和代码生成器的使用。
摘要由CSDN通过智能技术生成

基础简介

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

快速入门

基础CRUD的操作

准备:
首先让我们的数据库持久层的mapper继承一个baseMapper

package cn.supperbro.mybatisplustest.mapper;
import cn.supperbro.mybatisplustest.domain.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
@Repository
public interface UserMapper extends BaseMapper<User> {
}

将其放入spring的IOC容器当中,每次使用,直接自动装配

 @Autowired
    private UserMapper userMapper;
  1. insert into …
@Test
    public void testInsert(){
        User user = new User();
        user.setName("Marry");
        user.setAge(20);
        user.setEmail("1817566926@qq.com");
        System.out.println(userMapper.insert(user));
    }

在执行这个插入语句的时候,调用的是userMapper.insert()方法,不用再去手动书写sql语句。

 Parameters: 1433565591939190785(Long), Marry(String), 20(Integer), 1817566926@qq.com(String), 0(Integer), 2021-09-03 07:00:46.138(Timestamp), null

从插入的数据来看,我们没有给id赋值,然而却生成了一个Long类型的数据,是因为MyBatis有自动生成的id的策略,我们只需要添加注解就ok

 @TableId(type = IdType.ASSIGN_ID)
    private Long id;

对于 IdType这是一个枚举类型

package com.baomidou.mybatisplus.annotation;
public enum IdType {
    AUTO(0),
    NONE(1),
    INPUT(2),
    ASSIGN_ID(3),
    ASSIGN_UUID(4),
    /** @deprecated */
    @Deprecated
    ID_WORKER(3),
    /** @deprecated */
    @Deprecated
    ID_WORKER_STR(3),
    /** @deprecated */
    @Deprecated
    UUID(4);
    private final int key;
    private IdType(int key) {
        this.key = key;
    }
    public int getKey() {
        return this.key;
    }
}

自3.3.0开始,mybatis默认使用雪花算法+UUID(不含中划线)
在这里插入图片描述

  1. update…
 @Test
    public void testUpdate(){
        User user = new User();
        user.setId(1433565591939190785L);
        user.setName("Marry-Plus");
        System.out.println(userMapper.updateById(user));
    }

使用更新时,我们同样时调用方法就好了
但是从我们的更新语句中发现
UPDATE user SET name=?, version=?, update_time=? WHERE id=? AND version=?
自动添加了 version=?, update_time=?。
首先关于update_time
1.阿里巴巴开发手册中提到,每个数据库的表应该包括创建时间和更新时间两个字段,用于追踪到数据的修改,新增加的基本信息。
2.在mybatis中也有这样的机制:

 	@TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

3 根据FieldFill字段填充进行自动填充,配置生成策略

package cn.supperbro.mybatisplustest.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
//注入到spring并且去实现 MetaObjectHandler接口,实现方法
@Component
public class DateHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.setFieldValByName("createTime",new Date(),metaObject);
    }

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

关于version字段呢
首先需要了解的是乐观锁:简单理解就是非常乐观,认为所有的操作不会出现问题。乐观锁假设数据一般情况不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。乐观锁适用于读多写少的场景,这样可以提高程序的吞吐量。

当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:

1 取出记录时,获取当前version
2 更新时,带上这个version
3 执行更新时, set version = newVersion where version = oldVersion
4 如果version不对,就更新失败

配置springboot,定义一个配置类,注入

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

在实体类中加入注解字段:

 	@Version
    private int version;
  1. delete…
    对于删除操作,实际上我们是不希望对数据进行真正意义上的删除,也就是物理删除,我们希望进行逻辑删除。同样mybatis也存在这样的机制。

    说明:
    只对自动注入的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
    字段类型支持说明:

    支持所有数据类型(推荐使用 Integer,Boolean,LocalDateTime)
    如果数据库字段使用datetime,逻辑未删除值和已删除值支持配置为字符串null,另一个值支持配置为函数来获取值如now()

    附录:
    逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。
    如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。

配置文件

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)

注解

 @TableLogic
    private int flag;

测试

@Test
    public void testDelete(){
        System.out.println(userMapper.deleteById(1433565591939190785L));
    }

我们调用的虽然是delete方法,但是实际上它运行的却是:
UPDATE user SET flag=1 WHERE id=? AND flag=0

  1. select
@Test
    public void testSelect() {
        System.out.println(("----- selectAll method test ------"));
        List<User> userList = userMapper.selectList(null);
        for (User user : userList) {
            System.out.println(user);
        }
    }

但我们在设置了逻辑删除之后,查询也会遵循对应的原则,及不会去查找 flag = 1的元组

关于Wrapper

在进行条件查询时的时候,我们发现总是需要传递一个wrapper,那么wrapper如何定义呢。

官网链接

测试案例:

@Test
    public void testQueryWrapper01(){
        QueryWrapper<User> user = new QueryWrapper<>();
        //模糊查询,查询名字中含有J,并且邮箱以test开头的user
        user.like("name",'j').likeRight("email","test");
        userMapper.selectList(user).forEach(System.out::println);
    }

    @Test
    public void testQueryWrapper02(){
        QueryWrapper<User> user = new QueryWrapper<>();
        //查询id在2--8之间的元素
        user.between("id",2,8);
        userMapper.selectList(user).forEach(System.out::println);
    }

    @Test
    public void testQueryWrapper03(){
        QueryWrapper<User> user = new QueryWrapper<>();
        //查询id为1433565591939190785的元素
        user.eq("id",1433565591939190785L);
        userMapper.selectList(user).forEach(System.out::println);
    }

    @Test
    public void testQueryWrapper04(){
        QueryWrapper<User> user = new QueryWrapper<>();
        //查询id为1,3,6,10其中的元素
        user.in("id", Arrays.asList(1,3,6,100));
        userMapper.selectList(user).forEach(System.out::println);
    }

    @Test
    public void testQueryWrapper05(){
        QueryWrapper<User> user = new QueryWrapper<>();
        //查询createTime降序排列元素
        user.orderByDesc("create_time");
        userMapper.selectList(user).forEach(System.out::println);
    }

关于分页插件

配置,设置springboot配置类

//Spring boot方式
@Configuration
@MapperScan("com.baomidou.cloud.service.*.mapper*")
public class MybatisPlusConfig {

    // 旧版
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
        // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
        // paginationInterceptor.setOverflow(false);
        // 设置最大单页限制数量,默认 500 条,-1 不受限制
        // paginationInterceptor.setLimit(500);
        // 开启 count 的 join 优化,只针对部分 left join
        paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
        return paginationInterceptor;
    }
    
    // 最新版
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    } 
}

测试案例

@Test
    public void testLimitPage(){
        QueryWrapper<User> user = new QueryWrapper<>();
        //查询createTime降序排列元素
        user.orderByDesc("create_time");
        Page<User> page = new Page<>(1,5);
        userMapper.selectPage(page,user);
        page.getRecords().forEach(System.out::println);
    }

关于代码自动生成器

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

package cn.supperbro.mybatisplustest;

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.Arrays;

public class DivCodeGenerator {
    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.setAuthor("supperbro");
        //是否打开文件生成的win窗口
        gc.setOpen(false);
        //是否覆盖文件
        gc.setFileOverride(false);
        //去掉service的I前缀
        gc.setServiceName("%sService");
        //配置ID生成策略
        gc.setIdType(IdType.ASSIGN_ID);
        //配置日期格式
        gc.setDateType(DateType.ONLY_DATE);
        // 实体属性 Swagger2 注解
        gc.setSwagger2(true);
        mpg.setGlobalConfig(gc);

        //设置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://localhost:3306/jdbctest?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=UTF-8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        //数据库的类型
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        //模块名
        pc.setModuleName("demo");
        //包路径
        pc.setParent("cn.supperbro.mybatisplustest");
        //生成实体类
        pc.setEntity("domain");
        //生成mapper
        pc.setMapper("mapper");
        pc.setService("service");
        pc.setController("controller");
        mpg.setPackageInfo(pc);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        // 配置要映射的表名,多个用逗号隔开
        strategy.setInclude("user");
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setEntityLombokModel(true);//开启lombok
        strategy.setLogicDeleteFieldName("flag");//逻辑删除策略
        //自动填充配置
        TableFill create = new TableFill("create_time", FieldFill.INSERT);
        TableFill modify = new TableFill("create_time", FieldFill.INSERT_UPDATE);
        strategy.setTableFillList(Arrays.asList(create,modify));
        //乐观锁
        strategy.setVersionFieldName("version");
        //rest风格
        strategy.setRestControllerStyle(true);
        strategy.setControllerMappingHyphenStyle(true);

        mpg.setStrategy(strategy);
        mpg.execute();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值