简介

MybatisPlus概述

  • MyBatis Plus是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生(提供了快速使用mybatis的方式)。

    MybatisPlus特点

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

  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

    开发导入相关依赖

    ```java 普通Maven项目下的依赖 com.baomidou mybatis-plus 3.4.2

SpringBoot环境下的MP(项目中使用)

com.baomidou mybatis-plus-boot-starter 3.4.1

  1. **注意:如果想在mybatis-plus看打印的sql,可在application.yml(application.properties)配置:**
  2. ```xml
  3. #mybatis-plus配置控制台打印完整带参数SQL语句
  4. mybatis-plus:
  5. configuration:
  6. log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

MybatisPlus实现常规增删改操作

MybatisPlus实现插入操作

方法

# T为泛型
int insert(T entity);

测试代码

     /*
     * 要求:添加名为大宝贝的user数据
     * sql语句:insert into tb_user(xx,xx,xx,...) values (xx,xx,xx,....)
     * */
    @Test
    public void testAddUesr2ById() {
        User user = User.builder()
                .userName("大宝贝")
                .age(38)
                .name("wq")
                .password("123456")
                .build();
        int result = userMapper.insert(user);
        if (result > 0) {
            System.out.println("添加成功");
        }
        System.out.println("user = " + user);

    }

MybatisPlus主键生成策略-@TableId

注解@TableId介绍

@TableId注解作用:
    1.标识实体类中主键对应属性;
    2.定义主键生成策略;
@TableId使用:
    添加在实体类的主键对应的成员属性上即可;

代码展示

# 此代码在User实体类中
/**
* @TableId: 指定当前表的主键
*      value: 建立数据库主键字段与实体字段的对应关系
*      type: 设置主键生成策略,
*          默认情况下使用雪花算法
*          IdType.AUTO:使用数据库的主键自增
*/
@TableId(type = IdType.AUTO)
private Long id;
private String userName;
private String password;

MybatisPlus常用主键生成策略

生成策略 应用场景 特点
IdType.AUTO 数据库主键自增(确保数据库设置了 主键自增 否则无效) 1.使用数据库自带的主键自增值;
2.数据库自增的主键值会回填到实体类中;
3.数据库服务端生成的;
IdType.ASSIGN_ID 主键类型为number类型或数字类型String 1.MP客户端生成的主键值;
2.生成的主键值是数字形式的字符串
3.主键对应的类型可以是数字类型或者数字类型的字符串
4.底层基于雪花算法,让数据库的唯一标识也参与id的生成运算,保证id在分布式环境下,全局唯一(避免id的主键冲突问题);
IdType.ASSIGN_UUID 主键类型为 string(包含数字和字母组成) 1.生成的主键值包含数字和字母组成的字符串;
2.注意事项:如果数据库中主键值是number类型的,可不可用

普通列注解-@TableField

注意:

  • 通过@TableField(“表列名”) 指定映射关系,以下情况可以省略:
    • 名称一样
    • 数据库字段使用_分割,实体类属性名使用驼峰名称(自动开启驼峰映射)
  • 忽略某个字段的查询和插入 @TableField(exist = false) ```java // @TableName: 指定当前对象对应的数据库表 @TableName(“tb_user”) @Data @NoArgsConstructor @AllArgsConstructor @Builder public class User {

    /**

    • @TableId: 指定当前表的主键
    • value: 建立数据库主键字段与实体字段的对应关系
    • type: 设置主键生成策略,
    • IdType.NONE/ASSIGN_ID:默认情况下使用雪花算法
    • IdType.AUTO:使用数据库的主键自增
    • ASSIGN_UUID:使用UUID生成一个全局唯一字符串 */ @TableId(type = IdType.AUTO) private Long id; private String userName; private String password; // 建立数据库字段与实体字段的对应关系 @TableField(“与数据库字段名对应”) @TableField(“t_name”) private String name; private Integer age; // 忽略此字段 @TableField(exist = false) private String email; }
<a name="xr2M8"></a>
## MybatisPlus实现删除操作
```java
//根据entity 条件,删除记录
int delete(@Param( Constants . WRAPPER) Wrapper<T> wrapper);
//删除(根据ID批量删除)
int deleteBatchIds (@Param( Constants . COLLECTION) Collection<? extends Serializable> idList); 
//根据ID删除
int deleteById(Serializable id);
//根据columnMap 条件,删除记录
int deleteByMap(@Param(Constants . COLUMN MAP) Map<String, object> columnMap);

根据ID删除

 int count = userMapper.deleteById(8L);

根据ID集合批量删除

 List ids = new ArrayList();
        ids.add(6);
        ids.add(7);
userMapper.deleteBatchIds(ids);

根据Map条件删除

Map<String, Object> map = new HashMap<>();

//delete from tb_user where user_name = ? and age = ?
map.put("user_name","itcast");
map.put("age","18");

userMapper.deleteByMap(map);

测试代码

    /*
     * 要求:删除id为 16 的用户
     * sql语句:DELETE FROM tb_user WHERE id=?
     * */
    @Test
    public void testDelUesrById() {
        int result = userMapper.deleteById(2L);
        if (result > 0) {
            System.out.println("删除成功");
        }

    }

    /*
     * 要求:删除id为 15、14 的用户
     * sql语句:DELETE FROM tb_user WHERE id=? or id=?
     * sql语句:DELETE FROM tb_user WHERE id IN ( ? , ? )
     * */
    @Test
    public void testDelUesrByIds() {
        List<Long> list = new ArrayList<>();
        list.add(14L);
        list.add(15L);
        int result = userMapper.deleteBatchIds(list);
        if (result > 0) {
            System.out.println("删除成功");
        }
    }

    /*
     * 要求:删除user_name为王八衰 age 为22 的用户
     * sql语句:DELETE FROM tb_user WHERE user_name = ? AND age = ?
     * */
    @Test
    public void testDelUesrByCondition() {
        Map<String, Object> map = new HashMap<>();
        map.put("user_name", "王八衰");
        map.put("age", 22);
        int result = userMapper.deleteByMap(map);
        if (result > 0) {
            System.out.println("删除成功");
        }
    }

MybatisPlus实现更新操作

方法介绍

//根据whereEntity条件,更新记录
int update(@Param( Constants . ENTITY) T entity, @Param(Constants .WRAPPER) Wrapper<T> updatewrapper) ;
//根据ID修改
int updateById(@Param Constants . ENTITY) T entity);
只更新对象属性中被赋值的字段

测试代码

    /*
     * 修改用户id为 4 的username修改为 李催
     * sql语句:UPDATE tb_user SET user_name=? WHERE id=?
     */
    @Test
    public void testUpdate() {
        User user = User.builder().id(4L).userName("李催").build();
        int result = userMapper.updateById(user);
        if (result > 0) {
            System.out.println("更新成功");
        }
    }

MybatisPlus实现查询操作

//1根据ID查询
T selectById(Serializable id);
//1根据entity 条件,查询条记录
T select0ne(@Paran(Constants . MIRAPPER) Wrapper<T> queryhirapper);
//1查询(根据ID批量查询)
List<T> selectBatchIds(@Param(Constants . COLLECTION) Collection<? extends Serializable> idList);
//根据entity 条件,查询全部记录
List<T> selectList(@Param(Constants . MIRAPPER) Wrapper<T> queryWrapper);
//1查询(根据columnMap 条件)
List<T> selectByMap(@Param(Constants . COLUPN MAP) Map<String, object> columnMap);
//根据wirapper 条件,查询全部记录
List<Map<String, object>> selectMaps (@Param(Constants . WRAPPER) Wrapper<T> queryirapper);
//根据Wirapper条件,查询全部记录。注意: 只返回第一个字段的值
List<object> selectobjs(@Param(Constants .WRAPPER) irapper<T> queryhirapper);
//1根据entity 条件,查询全部记录(并页)
IPage<T> selectPage(IPage<T> page, @Param(Constants . MRAPPER) wrapper<T> querywrapper);
//1根据wrapper 条件,查询全部记录(并翻页)
IPageCMap<String, object>> selectMapsPage(IPage<T> page, @Param(Constants . MRAPPER) Hirapper<T> que
//1根据Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants .MRAPPER) wrapper<T> queryirapper);

MybatisPlus实现分页查询

配置分页查询拦截器

@Configuration
@MapperScan("com.itheima.mapper")
public class MybatisPlusConfig {

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }

}

测试代码

    /*
     * 要求:分页查询user数据,每页5条数据,查询第一页数据
     * sql语句:SELECT * FROM tb_user LIMIT 0,5
     * sql语句:SELECT * FROM tb_user LIMIT 5 (简写形式)
     */
    @Test
    public void testPage() {
        IPage<User> page = new Page<>(0, 5);
        IPage<User> result = userMapper.selectPage(page, Wrappers.emptyWrapper());
        System.out.println("result = " + result);
        System.out.println("------------------------");
        //获取分页得到的集合
        List<User> records = result.getRecords();
        for (User record : records) {
            System.out.println(record);
        }
        System.out.println("------------------------");
        //获取数据库中的总条数
        long total = result.getTotal();
        System.out.println("total = " + total);
    }

QueryWrapper查询与LambdaQueryWrapper查询

Wrapper接口介绍

/**
 * 基础比较查询
 *
 * Wrapper接口:
 *  1.QueryWrapper: 查询
 *    LambdaQueryWrapper
 *  2.UpdateWrapper: 增删改
 *    LambdaUpdateWrapper
 */

QueryWrapper常用API

eq( ) :  等于 =
ne( ) :  不等于 <>
gt( ) :  大于 >
ge( ) :  大于等于  >=
lt( ) :  小于 <
le( ) :  小于等于 <=
between ( ) :  BETWEEN 值1 AND 值2 
notBetween ( ) :  NOT BETWEEN 值1 AND 值2 
in( ) :  in
notIn( ) :not in

//sql中反向查询eg:not like  != 等等,查询时是不会走索引的;

测试代码

/*
     * 要求:查询用户中姓名包含"伤",密码为"123456",且年龄为19或者25或者29,查询结果按照年龄降序排序;
     * sql语句:SELECT * FROM tb_user WHERE (user_name LIKE ? AND password = ? AND age IN (?,?,?)) ORDER BY age DESC
     */
    @Test
    public void testConditions1Query() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.like("user_name", "伤")
                .eq("password", "123456")
                .in("age", 19, 25, 29)
                .orderByDesc("age");
        List<User> users = userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }

    }


    /*
     * 要求:查询用户中姓名包含"伤",密码为"123456",且年龄为19或者25或者29,查询结果按照年龄降序排序;
     * sql语句:SELECT user_name,age FROM tb_user WHERE (user_name LIKE ? AND password = ? AND age IN (?,?,?)) ORDER BY age DESC
     */
    @Test
    public void testConditions2Query() {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(User::getUserName, "伤")
                .eq(User::getPassword, "123456")
                .in(User::getAge, 19, 25, 29)
                .orderByDesc(User::getAge);
        List<User> users = userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }

    }

总结

  • 建议使用第二种方式,这种方式是的代码更加的有维护性
  • 第一种存在的原因:只有java jdk8以上的版本才支持第二种写法

    QueryWrapper逻辑查询or

    OR查询说明

    1.通过QueryWrapper多条件查询时,默认使用and关键字拼接SQL;
    2.通过QueryWrapper调用or()方法时,底层会使用or关键字拼接方法左右的查询条件;
    

    测试代码

      /*
       * 要求:查询用户密码为"123456",或者 age 为 20、21、22,并且要求每页显示5条,查询第二页的数         据;
       * sql语句:SELECT user_name,age FROM tb_user WHERE  password = ? or age IN (?,?,?)
       */
      @Test
      public void testConditionsOrQuery() {
          IPage<User> userPage = new Page<>(2, 5);
          LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
          wrapper.eq(User::getPassword, "123456")
                  .or()
                  .in(User::getAge, 20, 21, 22);
          IPage<User> userIPage = userMapper.selectPage(userPage, wrapper);
          List<User> records = userIPage.getRecords();
          for (User record : records) {
              System.out.println(record);
          }
      }
    

    QueryWrapper模糊查询like

    模糊查询常用方法

    like("表列名","条件值");     作用:查询包含关键字的信息,底层会自动添加匹配关键字,比如:%条件值%
    likeLeft("表列名","条件值"); 作用:左侧模糊搜索,也就是查询以指定条件值结尾的数据,比如:%条件值
    likeRight("表列名","条件值");作用:右侧模糊搜索,也就是查询以指定条件值开头的数据,比如:条件值%
    

    测试代码

      /**
       * 模糊查询
       */
      @Test
      public void testFind3(){
          QueryWrapper<User> wrapper = new QueryWrapper<>();
          wrapper.like("user_name","伤");
          // 查询所有
          //List<User> list = userMapper.selectList(null);
          List<User> list = userMapper.selectList(wrapper);
          for (User user : list) {
              System.out.println(user);
          }
      }
    

    QueryWrapper排序查询

    核心方法

    orderByAsc      升序排序
    orderByDesc     降序排序
    

    测试代码

    ```java /**
    • 排序查询
    • 先根据age升序排序,如果年龄相同则按照id降序排序 */ @Test public void testFind4(){ QueryWrapper wrapper = new QueryWrapper<>(); wrapper.orderByAsc(“age”).orderByDesc(“id”); // 查询所有 //List list = userMapper.selectList(null); List list = userMapper.selectList(wrapper); for (User user : list) {
       System.out.println(user);
      
      } }
<a name="aJK6E"></a>
### QueryWrapper限定字段查询
<a name="IWdvT"></a>
#### select方法说明
```java
MP查询时,默认将表中所有字段数据映射查询,但是有时我们仅仅需要查询部分字段信息,这是可以使用select()方法限定返回的字段信息,避免I/O资源的浪费;
如:wrapper.select("字段1","字段2",......)

代码测试

    /**
     * 指定查询字段
     */
    @Test
    public void testFind5(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("age").orderByDesc("id").select("id","user_name","age");
        // 查询所有
        //List<User> list = userMapper.selectList(null);
        List<User> list = userMapper.selectList(wrapper);
        for (User user : list) {
            System.out.println(user);
        }
    }

QueryWrapper实现分页条件查询

常用方法

//参数1:分页对象
//参数2:查询条件
mapper.selectPage(page,wrapper);

测试代码

     /*
     * 要求:查询用户密码为"123456"的数据,并且要求每页显示5条,查询第二页的数据;
     * sql语句:SELECT user_name,age FROM tb_user WHERE (user_name LIKE ? AND password = ?      * AND age IN (?,?,?)) ORDER BY age DESC
     */
    @Test
    public void testConditionsPageQuery() {
        IPage<User> userPage = new Page<>(1, 5);
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getPassword, "123456");
        IPage<User> userIPage = userMapper.selectPage(userPage, wrapper);
        List<User> records = userIPage.getRecords();
        for (User record : records) {
            System.out.println(record);
        }
    }

MybatisPlus实现Service封装

MybatisPlus封装Service介绍

说明

  • MybatisPlus为了开发更加快捷,对业务层也进行了封装,直接提供了相关的接口和实现类;
  • 我们在进行业务层开发时,可以继承它提供的接口和实现类,使得编码更加高效;

    实现流程

  • 定义一个服务扩展接口,该接口继承公共接口IService;

  • 定义一个服务实现类,该类继承ServiceImpl,并实现自定义的扩展接口;

    核心API

    image-20210801153025693.png

    MybatisPlus封装Service实现

    定义服务扩展接口

    //在公共接口的基础上扩展
    public interface UserService extends IService<User> {
    }
    

    定义服务实现

    @Service
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {}
    

    自动填充功能

    添加@TableField注解

    @TableField(fill = FieldFill.INSERT) //插入数据时进行填充
    private String password;
    

    编写MyMetaObjectHandler

    ```java package com.itheima.config;

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

import java.time.LocalDateTime;

/**

  • @author 12090
  • @dept 自动注入配置类 */ @Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override public void insertFill(MetaObject metaObject) {

     log.info("start insert fill ....");
     /**
      * 起始版本 3.3.3(推荐)
      * 注意:fieldName必须要和实体类中的属性名一致
      */
     this.strictInsertFill(metaObject, "createTime", () -> LocalDateTime.now(), LocalDateTime.class);
    

    }

    @Override public void updateFill(MetaObject metaObject) {

     log.info("start update fill ....");
     /**
      * 起始版本 3.3.3(推荐)
      */
     this.strictUpdateFill(metaObject, "updateTime", () -> LocalDateTime.now(), LocalDateTime.class);
    

    } } ```

    MybatisPlus代码生成器

    开源地址:https://gitee.com/jitheima/mp_generator.git
    或者使用MybatisX插件