MyBatis-Plus

发布时间 2023-11-18 18:09:15作者: yanggdgg
MyBatis-Plus官网:https://baomidou.com/

一、简介

1. 概述

MyBatis-Plus(简称 MP,是由baomidou(苞米豆)组织开源的)是一个基于 MyBatis 的增强工具,它对 Mybatis 的基础功能进行了增强,但未做任何改变。

使得我们可以在 Mybatis 开发的项目上直接进行升级为 Mybatis-plus,正如它对自己的定位,它能够帮助我们进一步简化开发过程,提高开发效率。

Mybatis-Plus 其实可以看作是对 Mybatis 的再一次封装,升级之后,对于单表的 CRUD 操作,调用 Mybatis-Plus 所提供的 API 就能够轻松实现,

此外还提供了各种查询方式、分页等行为。最最重要的,开发人员还不用去编写 XML,这就大大降低了开发难度。

2. 特性

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

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

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

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

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

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

  • 支持 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 注入攻击。

二、快速使用

1. 引入依赖

<dependencies>
    <!-- mybatis-plus框架 -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.2</version>
    </dependency>
    <!--mysql数据库-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.26</version>
    </dependency>
</dependencies>

2. 配置数据源

在application.yml/properties中配置数据源,此处省略

3. 创建实体类

4. 创建映射接口

需要继承BaseMapper<实体类名>,然后就可以直接使用了。

三、通用CRUD

1. 配置日志

使用SpringBoot默认的logback日志或MyBatis-plus集成的日志

MyBatis-Plus集成的日志:

mybatis-plus:
  configuration:
    #mybatis-plus日志控制台输出
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    #关闭banner
    banner: false

2. 插入操作

/**
* 插入一条记录
*
* @param entity 实体对象.
*/
int insert(T entity);

2.1 @TableId

名称@TableId
类型 属性注解
位置 模型类中用于表示主键的属性定义上方
作用 设置当前类中主键属性的生成策略
相关属性 value(默认):设置数据库表主键名称,字段名和属性名相同可以省略 type:设置主键属性的生成策略,值查照IdType的枚举值
/**
 * 生成ID类型枚举类
 */
@Getter
public enum IdType {
    /**
     * 数据库ID自增
     * <p>该类型请确保数据库设置了 ID自增 否则无效</p>
     */
    AUTO(0),
    /**
     * 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
     * 注解中指定为NONE使用全局的生成策略,默认使用雪花算法
     */
    NONE(1),
    /**
     * 用户输入ID
     * <p>该类型可以通过自己注册自动填充插件进行填充</p>
     */
    INPUT(2),

    /* 以下2种类型、只有当插入对象ID 为空,才自动填充。 */
    /**
     * 分配ID (主键类型为number或string)
     * 雪花算法生成id
     */
    ASSIGN_ID(3),
    /**
     * 分配UUID (主键类型为 string)
     */
    ASSIGN_UUID(4);
}
源码及注释
  1. AUTO:数据库ID自增,这种策略适合在数据库服务器只有1台的情况下使用,不可作为分布式ID使用。

  2. NONE(默认): 跟随全局的设置(默认使用雪花算法)。

  3. INPUT:手动输入或使用插件生成id。

  4. ASSIGN_ID:可以在分布式的情况下使用,生成的是Long类型的数字,可以排序性能也高,但是生成的策略和服务器时间有关,如果修改了系统时间就有可能导致出现重复主键。

  5. ASSIGN_UUID:可以在分布式的情况下使用,而且能够保证唯一,但是生成的主键是32位的字符串,长度过长占用空间而且还不能排序,查询性能也慢。

  6. 综上所述,每一种主键策略都有自己的优缺点,根据自己项目业务的实际情况来选择使用才是最明智的选择。

  • 雪花算法(SnowFlake),是Twitter官方给出的算法实现 是用Scala写的。其生成的结果是一个64bit大小整数,它的结构如下图:

 

  1. 1bit,不用,因为二进制中最高位是符号位,1表示负数,0表示正数。生成的id一般都是用整数,所以最高位固定为0。

  2. 41bit-时间戳,用来记录时间戳,毫秒级。

  3. 10bit-工作机器id,用来记录工作机器id,其中高位5bit是数据中心ID其取值范围0-31,低位5bit是工作节点ID其取值范围0-31,两个组合起来最多可以容纳1024个节点。

  4. 序列号占用12bit,每个节点每毫秒0开始不断累加,最多可以累加到4095,一共可以产生4096个ID。

2.2 修改id生成策略

1. 局部配置

 @TableId(type = IdType.AUTO) id自增策略

用在实体类的属性上

2. 全局配置

配置文件中配置:

mybatis-plus:
  global-config:
    db-config:
    	id-type: auto

注意:使用自增策略要求数据库中开启自动递增

2.3 映射匹配设置

1. @TableFiled

名称@TableField
类型 属性注解
位置 模型类属性定义上方
作用 设置当前属性对应的数据库表中的字段关系
相关属性 value(默认):设置数据库表字段名称 exist:设置属性在数据库表字段中是否存在,默认为true,此属性不能与value合并使用 select:设置属性是否参与查询,此属性与select()映射配置不冲突

2. @TableName

实体类与表名不一致可以手动指定表名。

名称@TableName
类型 类注解
位置 模型类定义上方
作用 设置当前类对应于数据库表关系
相关属性 value(默认):设置数据库表名称

也可以全局配置给实体类加上前缀:

mybatis-plus:
  global-config:
    db-config:
    	table-prefix: tbl_

3. 更新操作

在MP中有两种更新:根据Id更新,根据指定条件更新

3.1 根据Id更新

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

直接传入实体类,根据尸体了的Id进行修改:

  对于赋值了的属性进行修改,没有赋值的不进行修改。

3.2 根据条件更新

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

wrapper是条件的包装类

在wrapper中设置好条件后作为参数直接传入方法即可。

例如:

@Test
void contextLoads() {
    User user = new User();
    //设置更新的字段
    user.setEmail("Arvin@123.com");
    UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
    //设置更新的条件
    updateWrapper.eq("uid", 6L);
    int i = userMapper.update(user, updateWrapper);
}

结果:

 也可以用updateWrapper.set()设置更新的字段

//设置更新的字段
    updateWrapper.set("age", 28);

4. 删除操作

4.1 根据Id删除

/**
  * 根据 ID 删除
  *
  * @param id 主键ID
  */
int deleteById(Serializable id);

/**
  * 根据实体(ID)删除
  *
  * @param entity 实体对象
  * @since 3.4.4
  */
int deleteById(T entity);
//方式一
userMapper.deleteById(1);
//方式二
User user=new User();
user.setId=2;
userMapper.deleteById(user);

4.2 根据条指定字段删除

/**
  * 根据 columnMap 条件,删除记录
  *
  * @param columnMap 表字段 map 对象
  */
int deleteByMap(@Param(Constants.COLUMN_MAP) Map<String, Object> columnMap);

例:

@Test
void contextLoads() {
    Map<String, Object> columnMap = new HashMap<>();
    columnMap.put("uname","Jack");
    columnMap.put("age",20);

    //将columnMap中的键值对设置为删除的条件,多个之间为and关系
    int i = this.userMapper.deleteByMap(columnMap);
}

结果:

4.3 根据指定条件(wrapper)删除

/**
  * 根据 entity 条件,删除记录
  *
  * @param queryWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
  */
int delete(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

例:

@Test
void contextLoads() {
    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("uname", "Tom");
    queryWrapper.eq("age", "28");
    int i = userMapper.delete(queryWrapper);

}

结果:

 默认使用 AND 连接条件,如果用OR,调用 queryWrapper.or()即可。

4.4 根据id批量删除

/**
  * 删除(根据ID或实体 批量删除)
  *
  * @param idList 主键ID列表或实体列表(不能为 null 以及 empty)
  */
int deleteBatchIds(@Param(Constants.COLL) Collection<?> idList);

5. 查询操作