Mybatis-Plus快速入门

MyBatisPlus

通过扫描实体类,并基于反射获取实体类信息作为数据库信息

  • 类名驼峰转下划线作为表名
  • 为id的字段作为主键
  • 变量名驼峰转下划线作为表的字段名

遵守这些约定MyBatisPlus就会自动生成字段,方便我们快速实现

一、快速入门

  • 起步依赖

MyBatisPlus官方提供了starter,其中集成了Mybatis和MybatisPlus的所有功能,并且实现了自动装配效果。

因此我们可以用MybatisPlus的starter代替Mybatis的starter:

xml 复制代码
<!--mybatisplus-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.4.2</version>
</dependency>
  • 定义Mapper

自定义的Mapper继承Mybatis提供的BaseMapper接口,注意这里泛型需要指定为我们操作的类

java 复制代码
public interface UserMapper extends BaseMapper<User> {
}

这里面继承了很多方法,方便我们使用

二、常见注解

常见注解如下

  • @TableName:用来指定表名

    • 用法:类名和表名不一致
  • @Tableld:用来指定表中的主键字段信息

    • 用法:主键id和数据库中不一致

    • type字段 设置主键的策略(这里需要指定不然默认雪花算法自动生成)

  • @TableField:用来指定表中的普通字段信息

    • 用法:普通字段和数据库中不一致

    • 注意

      • 字段为 is开头的类型必须要指定否则mybatis会自动舍去掉is
      • 关键字冲突的必须要加上``
      • 数据库中不存在的字段需要标记

三、常见配置

MyBatisPlus的配置项继承了MyBatis原生配置和一些自己特有的配置。

yaml 复制代码
mybatis-plus:
  #别名扫描包
  type-aliases-package:
  #xml文件地址,默认值
  mapper-locations:
  configuration:
    map-underscore-to-camel-case: true #是否开启下划线和驼峰的映射
    cache-enabled: false #是否开启二级缓存
  global-config:
    db-config:
      id-type: assign_id #id为雪花算法生成
      update-strategy: not_null #更新策略:只更新非空字段

四、条件构造器

MyBatisPlus支持各种复杂的where条件,可以满足日常开发的所有需求。

QueryWrapper

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件

例子:查出名字带o,且存款大于等于1000的id,username,info

java 复制代码
        //构建查询条件
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .select("id","username","info","balance")
                .like("username","o")
                .ge("balance",1000);

        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);

例子:更新用户名为jack的余额为2000

java 复制代码
        //要更新的数据
        User user = new User();
        user.setBalance(2000);
        //构建更新条件
        QueryWrapper<User> wrapper = new QueryWrapper<User>()
                .eq("username","jack");
        userMapper.update(user,wrapper);

UpdateWrapper

继承自 AbstractWrapper ,自身的内部属性 entity 也用于生成 where 条件

例子:更新id为1,2,4的用户的余额,扣200

java 复制代码
        List<Long> ids = List.of(1L, 2L, 4L);
        //构建更新条件
        UpdateWrapper<User> wrapper = new UpdateWrapper<User>()
                .setSql("balance = balance - 200")
                        .in("id",ids);
        userMapper.update(null,wrapper);

LambdaWrapper

解决硬编码问题,推荐使用

java 复制代码
        //构建查询条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<User>()
                .select(User::getId,User::getUsername,User::getInfo,User::getBalance)
                .like(User::getUsername,"o")
                .ge(User::getBalance,1000);

        List<User> users = userMapper.selectList(wrapper);
        users.forEach(System.out::println);

五、自定义SQL

我们可以利用MyBatisPlus的Wrapper来构建复杂的Where条件,然后自己定义SQL语句中剩下的部分。

  • 基于Wrapper构建where条件
  • 在mapper方法参数中用Param注解声明wrapper变量名称,必须是ew
  • 自定义SQL并使用Wrapper条件

六、Service接口

MybatisPlus也提供了大量的service接口以便我们自己来使用

  • 根据上图,我们可以看到,我们继承它给我们提供的Impl和我们自己实现的接口,注意红色框中需要指定泛型

userService

userServiceImpl

6.1、普通实现

那么我们简单的业务逻辑就可以直接在Controller中实现进行

java 复制代码
    /**
     * 新增用户
     * @param userFormDTO
     */
    @PostMapping
    @ApiOperation("新增用户 ")
    public void addUser(@RequestBody UserFormDTO userFormDTO){
        //拷贝
        User User = new User();
        BeanUtils.copyProperties(userFormDTO,User);
        //执行新增
        userService.save(User);
    }

    @DeleteMapping("/{id}")
    @ApiOperation("删除用户 ")
    public void deleteUser(@ApiParam("用户id") @PathVariable Long id){
        //执行删除
        userService.removeById(id);
    }

当业务逻辑比较复杂的时候,我们就需要自己写。

当baseMapper提供的方法也不足以满足我们的需求,也需要自己写

6.2、lambda

查询

如果我们需要实现一个复杂的条件,例如下面这样

按照xml中我们就应该写成下面这种

而我们可以直接在serviceImpl中直接使用lambda快速构建

更新

这里必须要加update否则语句不会执行

6.3、批处理新增

如果在使用mysql数据库的时候,遇到批处理,MySQL的客户端连接参数中有这样的一个参数:rewriteBatchedStatements

修改项目中的application.yml文件,在jdbc的url后面添加参数&rewriteBatchedStatements=true:

然后使用mybatis的批处理,让性能达到最好

java 复制代码
@Test
void testSaveBatch() {
    // 准备10万条数据
    List<User> list = new ArrayList<>(1000);
    long b = System.currentTimeMillis();
    for (int i = 1; i <= 100000; i++) {
        list.add(buildUser(i));
        // 每1000条批量插入一次
        if (i % 1000 == 0) 
            //预编译sql,提升速度
            userService.saveBatch(list);
            list.clear();
        }
    }
    long e = System.currentTimeMillis();
    System.out.println("耗时:" + (e - b));
}

七、扩展功能

7.1、代码生成器

这里没有使用官方给我们提供的,我们直接使用插件

在Idea顶部菜单中,找到other,选择Config Database配置数据库地址

在弹出的窗口中填写数据库连接的基本信息:

jdbc:mysql://localhost:3306/xx?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC

然后再次点击Idea顶部菜单中的other,然后选择Code Generator:

然后就会自动生成我们需要的代码

7.2、静态工具

有的时候Service之间也会相互调用,为了避免出现循环依赖问题,MybatisPlus提供一个静态工具类:Db,其中的一些静态方法与IService中方法签名基本一致,也可以帮助我们实现CRUD功能:

java 复制代码
        List<Address> addresses = Db.lambdaQuery(Address.class).eq(Address::getId, id).list();

7.3、逻辑删除

逻辑删除就是基于代码逻辑模拟删除效果,但并不会真正删除数据。思路如下:

  • 在表中添加一个字段标记数据是否被删除
  • 当删除数据时把标记置为1
  • 查询时只查询标记为0的数据

增删改查那么我们都需要加上判断是否该数据处于删除状态

那么mybatisplus给我们提供了方法

只对自动注入的 sql 起效:

  • 插入: 不作限制
  • 查找: 追加 where 条件过滤掉已删除数据,如果使用 wrapper.entity 生成的 where 条件也会自动追加该字段
  • 更新: 追加 where 条件防止更新到已删除数据,如果使用 wrapper.entity 生成的 where 条件也会自动追加该字段
  • 删除: 转变为 更新

7.3.1、使用方法

  • 例: application.yml
yaml 复制代码
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注解
java 复制代码
@TableLogic
private Integer deleted;

7.3.2、注意

逻辑删除本身也有自己的问题,比如:

  • 会导致数据库表垃圾数据越来越多,影响查询效率.
  • SQL中全都需要对逻辑删除字段做判断,影响查询效率

因此,我不太推荐采用逻辑删除功能,如果数据不能删除,可以采用把数据迁移到其它表的办法。

7.4、枚举处理器

解决了繁琐的配置,让 mybatis 优雅的使用枚举属性!

  • 定义枚举类

要让MybatisPlus处理枚举与数据库类型自动转换,我们必须告诉MybatisPlus,枚举中的哪个字段的值作为数据库值。 MybatisPlus提供了@EnumValue注解来标记枚举属性:

@JsonValue注解表示标记JSON序列化时展示的字段

7.5、JSON处理器

数据库的user表中有一个info字段,是JSON类型:

JSON 复制代码
{"age": 20, "intro": "佛系青年", "gender": "male"}

而目前User实体类中却是String类型:

这样一来,我们要读取info中的属性时就非常不方便。如果要方便获取,info的类型最好是一个Map或者实体类

因此MybatisPlus提供了很多特殊类型字段的类型处理器,解决特殊字段类型与数据库类型转换的问题。例如处理JSON就可以使用JacksonTypeHandler处理器。

方法

  • 首先,我们定义一个单独实体类来与info字段的属性匹配:
Java 复制代码
package com.itheima.mp.domain.po;

import lombok.Data;

@Data
public class UserInfo {
    private Integer age;
    private String intro;
    private String gender;
}
  • 接下来,将User类的info字段修改为UserInfo类型,并声明类型处理器:

八、插件功能

8.1、分页插件

在项目中新建一个配置类:

java 复制代码
@Configuration
@MapperScan("scan.your.mapper.package")
public class MybatisPlusConfig {

    /**
     * 添加分页插件
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        //初始化核心插件
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //添加分页插件
        PaginationInnerInterceptor pageInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        pageInterceptor.setMaxLimit(1000L);//设置分页上线
        interceptor.addInnerInterceptor(pageInterceptor);//如果配置多个插件,切记分页最后添加

        //interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); 如果有多数据源可以不配具体类型 否则都建议配上具体的DbType
        return interceptor;
    }
}

编写一个分页查询的测试:

Java 复制代码
@Test
void testPageQuery() {
        // 1.分页查询,new Page()的两个参数分别是:页码、每页大小
        int pageNo =1,pageSize = 2;
        Page<User> page = Page.of(pageNo, pageSize);
        //设置排序条件
        page.addOrder(new OrderItem("balance",true));
        //2.分页查询
        Page<User> p = userService.page(page);

        // 总条数
        System.out.println("total = " + p.getTotal());
        // 总页数
        System.out.println("pages = " + p.getPages());
        // 数据
        List<User> records = p.getRecords();
        records.forEach(System.out::println);
}
相关推荐
heirui_Oooo几秒前
利用两种方式分别实现单例模式(懒汉式、饿汉式)
java·开发语言
天使day8 分钟前
Maven
java·maven
汇匠源10 分钟前
共享无人系统,从出行到生活全面覆盖
java·生活
小灰灰要减肥1 小时前
装饰者模式
java
张铁铁是个小胖子1 小时前
MyBatis学习
java·学习·mybatis
Yan.love2 小时前
开发场景中Java 集合的最佳选择
java·数据结构·链表
椰椰椰耶2 小时前
【文档搜索引擎】搜索模块的完整实现
java·搜索引擎
大G哥2 小时前
java提高正则处理效率
java·开发语言
智慧老师3 小时前
Spring基础分析13-Spring Security框架
java·后端·spring
lxyzcm3 小时前
C++23新特性解析:[[assume]]属性
java·c++·spring boot·c++23