Mybatis-Plus学习

本文介绍了Mybatis-Plus的基本概念,如何通过自动化CRUD操作节省开发时间,涵盖了主键生成、ActiveRecord模式、Lambda表达式、分页插件和性能分析等内容,适合快速上手Mybatis-Plus项目。
摘要由CSDN通过智能技术生成

Mybatis-Plus学习

Mybatis-Plus概述

为什么要学习他?MybatisPlus可以节省我们大量的工作时间,所有的CRUD代码它都可以自动化完成!

简介

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

快速开始

步骤(来自官网)

  1. 创建数据库

  2. 创建user表

    DROP TABLE IF EXISTS user;
    
    CREATE TABLE user
    (
    	id BIGINT(20) NOT NULL 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)
    );
    
  3. 插入数据

    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');
    
  4. 创建项目,并初始化。

  5. 添加依赖

    <!--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.0.5</version>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    

    说明:mybatis-plus可以帮我们节省大量代码的编写,尽量不要同时引入mybatis和mybatis-plus

  6. 连接数据库(注意文件后缀名为yml)

    spring:
      datasource:
        username: root
        password: 123456
        url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
        driver-class-name: com.mysql.cj.jdbc.Driver
    
    
  7. 编写User实体类

    package com.fmxu.pojo;
    
    import org.springframework.context.annotation.Configuration;
    
    /**
     * @author Dell
     * @projectName mybatis-plus
     * @description: user实体类
     * @date 2021/3/24/16:12
     */
    public class User {
    
        private Long id;
        private String name;
        private Integer age;
        private String email;
    
        public User() {
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getEmail() {
            return email;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        @Override
        public String toString() {
            return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
        }
    }
    
    
  8. 编写UserMapper接口

    package com.fmxu.mapper;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.fmxu.pojo.User;
    import org.apache.ibatis.annotations.Mapper;
    import org.springframework.stereotype.Repository;
    
    /**
     * @author Dell
     * @projectName mybatis-plus
     * @description: user的mapper接口
     * @date 2021/3/24/16:14
     */
    //继承基本的接口BaseMapper
    @Repository
    public interface UserMapper extends BaseMapper<User> {
    }
    
    
  9. 主启动类需要添加MapperScan注解,去扫描所有的mapper接口(包路径要写正确)

    @MapperScan("com.fmxu.mapper")
    @SpringBootApplication
    public class MybatisPlusApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MybatisPlusApplication.class, args);
        }
    
    }
    
  10. 测试类

    @SpringBootTest(classes = MybatisPlusApplication.class)
    class MybatisPlusApplicationTests {
    
        @Autowired
        private UserMapper userMapper;
        @Test
        void contextLoads() {
            List<User> users = userMapper.selectList(null);
            for (User user : users) {
                System.out.println(user);
            }
        }
    }
    

配置日志

我们所有的sql现在是不可见的,如果我们希望知道它是怎么运行的,我们就需要去配置日志!

在配置文件中配置

#日志配置
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

CRUD扩展

测试插入

@Test
public void testInsert(){
    User user=new User();
    user.setName("fmxu");
    user.setAge(24);
    user.setEmail("fmxu75@stu.xidian.edu.cn");

    userMapper.insert(user);  //帮我们自动生成id
}

主键生成策略

UUID,主键自增, 雪花算法…

主键自增

在实体类的主键上添加注解@TableId(type = IdType.AUTO)

其他的源码解释

public enum IdType {
    AUTO(0), //自增
    NONE(1),	//无操作
    INPUT(2),	//手动输入
    ID_WORKER(3),	//默认的全局唯一id
    UUID(4),	//全局唯一id uuid
    ID_WORKER_STR(5);	//字符串表示法
}

测试更新

@Test
public void testUpdate(){
    User user=new User();
    user.setName("xiaobai");
    user.setId(6L);

    userMapper.updateById(user);  
}

自动填充

创建时间、修改时间。这些操作一般都是自动化完成的,我们不希望手动更新。

方式一:数据库级别(不推荐使用)

表中新增字段,然后勾上更新选项

方式二:代码级别

  • 字段上添加注解

    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
    
  • 自定义实现类 MyMetaObjectHandler

    //将组件加入到IOC容器中
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
        //插入时的填充操作
        @Override
        public void insertFill(MetaObject metaObject) {
            this.setFieldValByName("createTime",new Date(),metaObject);
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
    
        //更新时的填充操作
        @Override
        public void updateFill(MetaObject metaObject) {
            this.setFieldValByName("updateTime",new Date(),metaObject);
        }
    }
    

乐观锁、悲观锁

乐观锁:它总是认为不会出现问题,无论干什么都不会加锁!如果出现问题,再次更新值测试

悲观锁:它认为干什么都会出现问题,无论干什么都会上锁!再去操作

乐观锁机制

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

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

乐观锁测试

  1. 首先数据库要添加一个乐观锁字段

  2. 实体类中添加乐观锁属性,并添加@Version注解

    @Version
    private Integer version;
    
  3. 注册组件

    //扫描我们的mapper文件夹
    @MapperScan("com.fmxu.mapper")
    @EnableTransactionManagement
    @Configuration
    public class MyBatisPlusConfig{
        //注册乐观锁
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor(){
            return new OptimisticLockerInterceptor();
        }
    }
    

查询操作

@Test
public void testSelectById(){
    User user=userMapper.selectById(1L);
    System.out.println(user);
}

//测试批量查询
@Test
public void testSelectByBatchId(){
    List<User> users=userMapper.selectBatchIds(Arrays.asList(1,2,3));
    for (User user : users) {
        System.out.println(user);
    }
}

//按条件查询之一使用map操作
@Test
public void testSelectByMap(){
    HashMap<String,Object> map=new HashMap<>();
    map.put("name","fmxu");
    map.put("age","24");
    List<User> users = userMapper.selectByMap(map);
    for (User user : users) {
        System.out.println(user);
    }
}

分页查询

分页在网站的使用非常多!

  1. 原始的limit进行分页
  2. pageHelper第三方插件
  3. MP其实也内置了分页插件

如何使用!

  1. 配置拦截器组件

    // 分页插件
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
    
  2. 测试

    //测试分页查询
    @Test
    public void testPage(){
        //参数1 当前页  参数2 页面大小
        Page<User> page = new Page<>(1, 5);
        userMapper.selectPage(page, null);
        for (User record : page.getRecords()) {
            System.out.println(record);
           
        }
    }
    

删除操作

//测试删除
@Test
public void testDeleteById(){
    userMapper.deleteById(1L);
}

//通过id批量删除
public void testDeleteBatchIds(){
    userMapper.deleteBatchIds(Arrays.asList(1,2,3));
}

//通过map删除
public void testDeleteMap(){
    HashMap<String, Object> map = new HashMap<>();
    map.put("name","fmxu");
    userMapper.deleteByMap(map);
}

逻辑删除

物理删除:从数据库中删除

逻辑删除:数据库中并没有被删除,而是通过一个变量将其失效。类似于回收站。

  1. 数据库中添加一个deleted字段

  2. 实体类中添加属性

    //逻辑删除
    @TableLogic 
    private int deleted;
    
  3. 在自定义的配置类中添加组件

    //逻辑删除组件
    @Bean
    public ISqlInjector sqlInjector(){
        return new LogicSqlInjector();
    }
    
  4. 配置主配置文件application.yml

    mybatis-plus:
      # 配置逻辑删除
      global-config:
        db-config:
          logic-delete-value: 1
          logic-not-delete-value: 0
    
  5. 测试

    删除后相应记录的deleted字段值由0变为1。假性删除。

条件构造器

参数说明

  1. eq 等于 =

    eq(R column, Object val) 
    eq(boolean condition, R column, Object val)
    
  2. allEq 全部eq(或个别isNull)

    allEq(Map<R, V> params)
    allEq(Map<R, V> params, boolean null2IsNull)
    allEq(boolean condition, Map<R, V> params, boolean null2IsNull)
    

    个别参数说明:

    params : key为数据库字段名,value为字段值
    null2IsNull : 为true则在mapvaluenull时调用 isNull 方法,为false时则忽略valuenull

    • 例1: allEq({id:1,name:"老王",age:null})—>id = 1 and name = '老王' and age is null
    • 例2: allEq({id:1,name:"老王",age:null}, false)—>id = 1 and name = '老王'
  3. ne 不等于

    ne(R column, Object val)
    ne(boolean condition, R column, Object val)
    
  4. gt 大于>

    • 例: gt("age", 18)—>age > 18
  5. lt 小于<

    • 例: lt("age", 18)—>age < 18
  6. le 小于等于<=

    • 例: le("age", 18)—>age <= 18
  7. between BETWEEN 值1 AND 值2

    • 例: between("age", 18, 30)—>age between 18 and 30
  8. notBetween NOT BETWEEN 值1 AND 值2

    • 例: notBetween("age", 18, 30)—>age not between 18 and 30
  9. like LIKE '%值%

    • 例: like("name", "王")—>name like '%王%'
  10. notLike NOT LIKE '%值%

    • 例: notLike("name", "王")—>name not like '%王%'
  11. likeLeft LIKE ‘%值’

    • 例: likeLeft("name", "王")—>name like '%王'
  12. likeRight LIKE ‘值%’

    • 例: likeRight("name", "王")—>name like '王%'
  13. isNull 字段 IS NULL

    • 例: isNull("name")—>name is null
  14. isNotNull 字段 IS NOT NULL

    • 例: isNotNull("name")—>name is not null
  15. in

    in(R column, Collection<?> value)
    in(boolean condition, R column, Collection<?> value)
    
    • 字段 IN (value.get(0), value.get(1), …)

    • 例: in("age",{1,2,3})—>age in (1,2,3)

    in(R column, Object... values)
    in(boolean condition, R column, Object... values)
    
    • 字段 IN (v0, v1, …)
    • 例: in("age", 1, 2, 3)—>age in (1,2,3)
  16. notIn

    notIn(R column, Collection<?> value)
    notIn(boolean condition, R column, Collection<?> value)
    
    • 字段 NOT IN (value.get(0), value.get(1), …)
    • 例: notIn("age",{1,2,3})—>age not in (1,2,3)
    notIn(R column, Object... values)
    notIn(boolean condition, R column, Object... values)
    
    • 字段 NOT IN (v0, v1, …)
    • 例: notIn("age", 1, 2, 3)—>age not in (1,2,3)
  17. inSql

    • 字段 IN ( sql语句 )
    • 例: inSql("age", "1,2,3,4,5,6")—>age in (1,2,3,4,5,6)
    • 例: inSql("id", "select id from table where id < 3")—>id in (select id from table where id < 3)
  18. notInSql

    • 字段 NOT IN ( sql语句 )
    • 例: notInSql("age", "1,2,3,4,5,6")—>age not in (1,2,3,4,5,6)
    • 例: notInSql("id", "select id from table where id < 3")—>id not in (select id from table where id < 3)
  19. groupBy

    • 分组:GROUP BY 字段, …
    • 例: groupBy("id", "name")—>group by id,name
  20. orderByAsc //正序

    • 排序:ORDER BY 字段, … ASC
    • 例: orderByAsc("id", "name")—>order by id ASC,name ASC
  21. orderByDesc //逆序

    • 排序:ORDER BY 字段, … DESC
    • 例: orderByDesc("id", "name")—>order by id DESC,name DESC
  22. orderBy

    orderBy(boolean condition, boolean isAsc, R... columns)
    
    • 排序:ORDER BY 字段, …
    • 例: orderBy(true, true, "id", "name")—>order by id ASC,name ASC
  23. having

    • HAVING ( sql语句 )
    • 例: having("sum(age) > 10")—>having sum(age) > 10
    • 例: having("sum(age) > {0}", 11)—>having sum(age) > 11
  24. func

    • unc 方法(主要方便在出现if…else下调用不同方法能不断链)
    • 例: func(i -> if(true) {i.eq("id", 1)} else {i.ne("id", 1)})
  25. or

    • 拼接 OR

      注意事项:

      主动调用or表示紧接着下一个方法不是用and连接!(不调用or则默认为使用and连接)

    • 例: eq("id",1).or().eq("name","老王")—>id = 1 or name = '老王'

    • OR 嵌套

    • 例: or(i -> i.eq("name", "李白").ne("status", "活着"))—>or (name = '李白' and status <> '活着')

  26. and

    • AND 嵌套
    • 例: and(i -> i.eq("name", "李白").ne("status", "活着"))—>and (name = '李白' and status <> '活着')
  27. nested

    • 正常嵌套 不带 AND 或者 OR
    • 例: nested(i -> i.eq("name", "李白").ne("status", "活着"))—>(name = '李白' and status <> '活着')
  28. apply

    • 拼接 sql
  29. last

    • 无视优化规则直接拼接到 sql 的最后

      注意事项:

      只能调用一次,多次调用以最后一次为准 有sql注入的风险,请谨慎使用

  30. exists

    • 拼接 EXISTS ( sql语句 )
    • 例: exists("select id from table where age = 1")—>exists (select id from table where age = 1)
  31. notExists

    • 拼接 NOT EXISTS ( sql语句 )
    • 例: notExists("select id from table where age = 1")—>not exists (select id from table where age = 1)

测试例子

package com;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fmxu.MybatisPlusApplication;
import com.fmxu.mapper.UserMapper;
import com.fmxu.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Queue;

@SpringBootTest(classes = MybatisPlusApplication.class)
class WrapperTests {

    @Autowired
    private UserMapper userMapper;
    @Test
    void contextLoads() {
        //查询name不为空的用户,并且邮箱不为空的用户,年龄大于等于12
        QueryWrapper<User> wrapper=new QueryWrapper<>();
            wrapper
                    .isNotNull("name")
                    .isNotNull("email")
                    .ge("age",24);
        List<User> users = userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    public void test2(){
        //查询名为fmxu的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name", "fmxu");
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }


    @Test
    public void test3(){
        //查询年龄在20~30中间的用户
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",20,30);
        List<User> users = userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }

    //模糊查询
    @Test
    public void test4(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.notLike("name","J")
                .likeRight("email","t");
        List<User> users = userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }

    //排序
    @Test
    public void test5(){
        //通过id排序
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.orderByDesc("id");
        List<User> users = userMapper.selectList(wrapper);
        for (User user : users) {
            System.out.println(user);
        }
    }

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值