MyBatisPlus笔记

一、MyBatisPlus概述


MyBatisPlus(简称 MP)是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。

MyBatis-Plus可以节省我们大量工作时间,所有的CRUD代码它都可以自动化完成!

同类技术框架有:JPA、tk-mapper、MyBatis-Plus。

MyBatisPlus官网地址:https://mybatis.plus/、https://baomidou.com/

MyBatisPlus项目地址:https://gitee.com/baomidou/mybatis-plus

在这里插入图片描述

在这里插入图片描述


分布式系统唯一ID生成方案汇总 - nick hao - 博客园 (cnblogs.com)

MyBatisPlus特性:

  • 无侵入:只做增强不做改变,不会对现有工程产生影响。
  • 损耗小:启动即会自动注入基本 CRUD(增删改查),性能基本无损耗,直接面向对象操作。
  • 强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表CRUD 操作,更有强大的条件构造器(QueryWrapper),满足各类使用需求。
  • 支持 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 操作智能分析阻断,也可自定义拦截规则,预防误操作。

MyBatisPlus支持的数据库:(任何能使用MyBatis进行CRUD操作,并且支持标准 SQL 的数据库)

  • mysql 、mariadb 、oracle 、db2 、h2 、hsql 、sqlite 、postgresql 、sqlserver 、presto 、Gauss 、Firebird。

  • Phoenix 、clickhouse 、Sybase ASE 、 OceanBase 、达梦数据库 、虚谷数据库 、人大金仓数据库 、南大通用数据库。


MyBatisPlus框架结构:

在这里插入图片描述


二、MyBatisPlus快速入门


文档地址:https://mybatis.plus/guide/quick-start.html

使用第三方组件的流程:
1、导入对应的依赖。
2、研究依赖如何配置。
3、代码如何编写。
4、提高扩展技术能力!


SpringBoot整合MP操作步骤如下:

1、准备数据:

create database if not exists mp_db character set utf8;
use mp_db;
CREATE TABLE user (
            id bigint(20) primary key auto_increment,
            name varchar(32) not null,
            password  varchar(32) not null,
            age int(3) not null ,
            tel varchar(32) not null
);
insert into user values(null,'tom','123456',12,'12345678910');
insert into user values(null,'jack','123456',8,'12345678910');
insert into user values(null,'jerry','123456',15,'12345678910');
insert into user values(null,'tom','123456',9,'12345678910');
insert into user values(null,'snake','123456',28,'12345678910');
insert into user values(null,'张益达','123456',22,'12345678910');
insert into user values(null,'张大炮','123456',16,'12345678910');

在这里插入图片描述


2、创建一个maven工程。

3、导入依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.baidou</groupId>
    <artifactId>mp01_quickstart</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!--父工程-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <dependencies>
        <!-- MySQL驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
        </dependency>

        <!-- lombok,通过注解简化实体类的开发 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!-- mybatisplus的起步依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>
        
        <!-- Junit起步依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
</project>

在这里插入图片描述

在这里插入图片描述


4、编写实体类:(类名与表名对应,属性名与字段名对应)(ORM对象关系映射)

package com.baidou.entity;

import lombok.Data;
//实体类
@Data
public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;
}

5、在application.yml文件中配置jdbc相关参数:

# 配置数据源
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/mp_db?useSSL=false
    username: root
    password: 123456

# 配置日志级别为:debug (输出大于等于debug级别的日志信息)
#logging:
#  level:
#    com.baidou: debug
    
# mp配置
mybatis-plus:
  configuration:
    # 配置标准sql输出
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl    

在这里插入图片描述


6、定义mapper接口,继承BaseMapper。

package com.baidou.mapper;

import com.baidou.entity.User;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

//在对应的Mapper上面继承BaseMapper接口

//@Repository //代表持久层
@Mapper
public interface UserMapper extends BaseMapper<User> {
    //所有的CRUD操作都已经编写完成了
    //你不需要像以前配置一大堆文件了!
}

在这里插入图片描述


7、定义启动类,并配置mapper扫描:

package com.baidou;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.baidou.mapper") //扫描我们的mapper包下的所有接口 
public class MyBatisPlusApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyBatisPlusApplication.class, args);
    }
}

8、编写测试

package com.baidou.test;

import com.baidou.entity.User;
import com.baidou.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

/**
 * 测试类
 *
 * @author 白豆五
 * @version 2023/1/23
 * @since JDK8
 */
@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    @Test
    public void testFindAll() {
        List<User> userList = userMapper.selectList(null); //null表示不传条件参数Wrapper
        for (User user : userList) {
            System.out.println(user);
        }
    }
}

运行结果:

在这里插入图片描述

SQL谁帮我们写的? MyBatisPlus都写好了。
方法哪里来的? MyBatisPlus都写好了。


三、标准数据层开发


mapper接口

1. MyBatisPlus的CRUD操作


功能之前自定义的接口MP提供的接口
新增boolean save(T entity)int insert(T entity)
删除boolean delete(int id)int deleteById(Serializable id)
修改boolean update(T entity)int updateById(T entity)
根据id查询T getById(int id)T selectById(Serializable id)
查询全部List getAll()List selectList()
分页查询PageInfo getAll(int age,int size)IPage selectPage(IPage page)
按条件查询List getAll(Condition condition)IPage selectPage(Wrapper queryWrapper)

示例代码:

package com.baidou.test;

import com.baidou.entity.User;
import com.baidou.mapper.UserMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;

/**
 * 测试mapper接口的crud操作
 *
 * @author 白豆五
 * @version 2023/1/23
 * @since JDK8
 */
@SpringBootTest
public class UserMapperTest {

    @Autowired
    private UserMapper userMapper;

    // 查询全部
    @Test
    public void testFindAll() {
        List<User> userList = userMapper.selectList(null); //null表示不传条件参数
        for (User user : userList) {
            System.out.println(user);
        }
    }

    // 新增,会自动返回新增记录的主键
    @Test
    public void testSave() {
        User user = new User();
        user.setName("小舞");
        user.setAge(18);
        user.setPassword("123456");
        user.setTel("13212341234");

        int num = userMapper.insert(user);

        if (num==1){
            System.out.println("添加成功");

            //自动返回新增记录的主键
            Long id = user.getId();
            System.out.println("用户的id:"+id);//1617500546355167234
        }
    }

    // 修改
    @Test
    public void testUpdate() {
        User user = new User();
        user.setId(5L);
        user.setName("小米");
        userMapper.updateById(user);
    }


    // 删除
    @Test
    public void testDelete() {
        userMapper.deleteById(1527307439025266690L);
    }
}

2. MyBatisPlus分页功能


MyBatisPlus内置分页插件。

2.1 MyBatisPlus分页功能接口


// 分页查询
IPage<T> selectPage(IPage<T> page)

2.2 MyBatisPlus分页使用


1、配置分页拦截器组件

package com.baidou.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 *MybatisPlus的配置类
 * @author 白豆五
 * @version 2023/1/23
 * @since JDK8
 */

@Configuration
public class MybatisPlusConfig {

    // 注册分页插件
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        //1 创建MP拦截器对象
        MybatisPlusInterceptor mpInterceptor=new MybatisPlusInterceptor();
        //2 添加分页拦截器
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        
        //注意:不同的数据库在开启分页功能的时候,需要设置成对应的数据库类型 (数据库方言不太一样)
        //mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return mpInterceptor;
    }
}

在这里插入图片描述


2、开启MyBatisPlus日志

# 开启mp的sql日志
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

3、编写测试

// 分页查询
@Test
public void testSelectPage() {
    // 1.创建IPage分页对象,设置分页参数
    // 参数一:当前页
    // 参数二: 页面大小
    IPage<User> page = new Page<>(1, 3);//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;

    // 2.执行分页查询
    userMapper.selectPage(page, null);

    // 3.获取分页结果
    System.out.println("当前页码值:" + page.getCurrent());
    System.out.println("每页显示数:" + page.getSize());
    System.out.println("总页数:" + page.getPages());
    System.out.println("总条数:" + page.getTotal());
    System.out.println("当前页数据:" + page.getRecords());
}

运行结果:

在这里插入图片描述


扩展:解决日志打印过多问题

1、取消初始化spring日志打印

在这里插入图片描述

解决方案:在resources下新建一个logback.xml文件,名称固定,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>

</configuration>
  • logback常用配置:https://www.jianshu.com/p/75f9d11ae011

2、关闭springboot启动的beanner图标

spring:
  main:
    banner-mode: off # 关闭SpringBoot启动图标(banner)

3、关闭MybatisPlus启动的beanner图标

mybatis-plus:
  global-config:
    banner: off # 关闭mybatisplus启动图标

四、DQL编程控制


DQL数据查询语言,查询操作的。

1. 条件查询方式


MyBatisPlus将书写复杂的SQL查询条件进行了封装,使用编程的形式完成查询条件的组合。

Wrapper条件构造器(抽象父类):

  • 子类:QueryWrapper (封装查询条件)、UpdateWrapper (封装修改条件)
  • 子类:LambdaUpdateWrapper、LambdaQueryWrapper(lambda格式查询条件)
    在这里插入图片描述

在这里插入图片描述


1.1 条件查询


方式1:条件查询(QueryWrapper)
@SpringBootTest
public class UserMapperTest {
ZSXT6
    @Autowired
    private UserMapper userMapper;

    /**
     * 按条件查询
     */
    @Test
    public void testQueryWrapper() {
        // 1、创建条件构造器对象
        QueryWrapper<User> qw = new QueryWrapper<>();
        // 2、封装条件:年龄小于18
        // lt小于, gt大于  (带t的)
        // eq 等于, ge 大于等于 ,le小于等于,ne不等于 (带e的)
        qw.lt("age", 18);
        // 3、mp按照指定条件进行查询所有操作
        List<User> userList = userMapper.selectList(qw);
        System.out.println(userList);
    }
}

在这里插入图片描述


方式2:条件查询——使用lambda表达式(QueryWrapper)
@Test
public void testQueryWrapperByLambda() {
    QueryWrapper<User> qw = new QueryWrapper<User>();
    qw.lambda().lt(User::getAge, 10); //LambdaQueryWrapper.lt(User::getAge, 10);
    List<User> userList = userMapper.selectList(qw);
    System.out.println(userList);
}

在这里插入图片描述


方式3:lambda格式条件查询(LambdaQueryWrapper)
@Test
public void testLambdaQueryWrapper() {
    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
    lqw.lt(User::getAge, 10);
    List<User> userList = userMapper.selectList(lqw);
    System.out.println(userList);
}

在这里插入图片描述


1.2 组合条件


并且关系(and)
// and : (10,25)
@Test
public void test1() {
    LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
    qw.lt(User::getAge,25).gt(User::getAge,10); // where age< 25 and age >10
    List<User> users = userMapper.selectList(qw);
    System.out.println(users);
}

// and : (10,25)
@Test
public void test2() {
    LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
    qw.lt(User::getAge,25).gt(User::getAge,10); // where age< 25 and age >10
    List<User> users = userMapper.selectList(qw);
    System.out.println(users);
}

在这里插入图片描述

注意:组合查询默认使用and。


或者关系(or)
@Test
public void test() {
    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
    //或者关系:小于10岁或者大于30岁
    lqw.lt(User::getAge, 10).or().gt(User::getAge, 30);//where age<10 or age>30
    List<User> userList = userMapper.selectList(lqw);
    System.out.println(userList);
}

在这里插入图片描述


1.3 NULL值处理


NULL值处理:先对条件值进行非空判断,然后再追加处理。

① if语句控制条件追加

先使用if非空校验然后再追加条件

@Test
public void test1() {
    Integer minAge=10;  //将来有用户传递进来,此处简化成直接定义变量了
   					 //包装类型数据 不传值默认为null
    Integer maxAge=null;  //将来有用户传递进来,此处简化成直接定义变量了
    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
    if(minAge!=null){
        lqw.gt(User::getAge, minAge);
    }
    if(maxAge!=null){
        lqw.lt(User::getAge, maxAge);
    }
    List<User> userList = userMapper.selectList(lqw);
    userList.forEach(System.out::println);
}

在这里插入图片描述


② 条件参数控制

简化第一种方式的if判断

@Test
public void test2() {
    Integer minAge = 20;
    Integer maxAge = null;
    LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<User>();
    //参数1:如果表达式为true,那么查询才使用该条件
    // (boolean condition, R column, Object val)
    lqw.gt(minAge != null, User::getAge, minAge);
    lqw.lt(maxAge != null, User::getAge, maxAge);
    userMapper.selectList(lqw);
}

在这里插入图片描述


③ 条件参数控制(链式编程)
@Test
public void test3() {
    Integer minAge = null;
    Integer maxAge = 18;
    LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
    qw.gt(minAge != null, User::getAge, minAge);
    qw.or();
    qw.lt(maxAge != null, User::getAge, maxAge);
    userMapper.selectList(qw);
}

在这里插入图片描述


2. 投影查询


投影查询:(设置查询字段、)

2.1 查询结果包含模型类中部分属性(设置查询字段)


@Test
public void test1() {
    // 投影查询,设置查询字段
    QueryWrapper<User> qw = new QueryWrapper<>();
    qw.select("id","name","age","tel"); //设置查询字段
    List<User> users = userMapper.selectList(qw);
    System.out.println(users);
}


2.2 查询结果包含实体类中未定义的属性(分组)


@Test
public void test2() {
    // 投影查询,分组查询
    QueryWrapper<User> qw = new QueryWrapper<>();
    // select xxxx from 表名
    qw.select("name,count(*)"); //sql: select name,count(*) from user group by name;
    qw.groupBy("name");
    List<Map<String, Object>> maps = userMapper.selectMaps(qw);
    System.out.println(maps);
}

在这里插入图片描述


3. 查询条件设定


多条件查询有哪些组合?

  • 范围匹配(>大于gt 、 >=大于等于ge、<小于lt、<=小于等于le、!=不等于ne 、between)
  • 模糊匹配(like)
  • 非空判断(null)
  • 包含性匹配(in)
  • 排序(order)

……


3.1 范围查询


范围查询:大于gt 、 大于等于ge、小于lt、相等eq、不相等ne 、小于等于le、between。

1、eq的使用

// eq
@Test
public void testEQ() {
    // 模拟用户登录
    String name="小米";
    String password="1234568";
    LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
    qw.eq(User::getName,name).eq(User::getPassword,password);
    User user = userMapper.selectOne(qw);
    System.out.println(user);
}

在这里插入图片描述


2、其他范围查询

//范围查询 ge(great then or equal) le(less then or equal)  gt lt  between
@Test
public void testRange() {
    /*
        (15,25)  qw.gt(User::getAge,15).lt(User::getAge,25);
        [15,25)  qw.ge(User::getAge,15).lt(User::getAge,25);
        (15,25]  qw.gt(User::getAge,15).le(User::getAge,25);
        [15,25]  qw.ge(User::getAge,15).le(User::getAge,25);
         */
    //[15,25]
    LambdaQueryWrapper<User> qw = new LambdaQueryWrapper<>();
    //qw.ge(User::getAge,15).le(User::getAge,25); // age>=15 and age <25
    qw.between(User::getAge, 15, 25); //使用between简化上面的写法
    List<User> users = userMapper.selectList(qw);
    System.out.println(users);
}

在这里插入图片描述


3.2 模糊匹配


模糊查询:like、likeLeft、likeRight

@Test
public void testLike() {
    QueryWrapper<User> qw = new QueryWrapper<>();
    // 匹配中间内容是xxx的
    // qw.like("name","a"); //  select * from user where name like %a%
    // 匹配以xxx结尾
    qw.likeLeft("name","炮"); //  select * from user where name like  %炮
    // 匹配以xxx开头
    qw.likeRight("name","小"); //  select * from user where name like 小%   
    List<User> users = userMapper.selectList(qw);
    System.out.println(users);
}

在这里插入图片描述


3.3 排序查询


排序:降序orderByDesc、升序orderByAsc。

@Test
public void testOrder(){
    QueryWrapper<User> qw = new QueryWrapper<>();
    qw.orderByDesc("age"); // select * from user order by age desc
    List<User> users = userMapper.selectList(qw);
    System.out.println(users);
}

在这里插入图片描述


3.4 包含性匹配


包含: in

// 包含:in
@Test
public void testIn(){
    QueryWrapper<User> qw = new QueryWrapper<>();
    qw.in("age",16,18,20);
    List<User> users = userMapper.selectList(qw);
    System.out.println(users);
}

在这里插入图片描述

巴拉巴拉


4. 字段映射与表名映射


4.1 解决表字段与实体类中属性名称不同步问题

解决方案:在实体类属性上,使用属性注解@TableField,通过value属性,设置当前属性对应的数据库表中的字段关系。

在这里插入图片描述

4.2 问题二:实体类中添加了数据库中未定义的属性

解决方案:在实体类属性上使用@TableField注解,通过exist属性,设置属性在数据库表字段中是否存在,默认为true。此属性无法与value合并使用。

在这里插入图片描述


4.3 解决采用默认查询会开放更多的字段查看权限

例如我们不想把查询的密码直接暴露给接口。

解决方案:在实体类属性上使用@TableField注解,通过select属性:设置该属性是否参与查询。此属性与value映射配置不冲突。

在这里插入图片描述
在这里插入图片描述


4.4 解决表名与实体类名不同步问题

解决方案:在实体类上使用@TableName注解,通过value属性,设置当前类对应的数据库表名称。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


扩展:

如果有许多实体都需要这样配置表名(例如开头是tb_xxx或tbl_xxx),可以在mp的全局配置中设置表的前缀。

mybatis-plus:
  global-config: #全局配置
    db-config:
      table-prefix: tb_  #设置表的前缀

这样实体类就不用再配置@TableName了。

package com.baidou.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;

@Data
public class User {
    private Long id;
    private String name;
    @TableField(value = "password",select = false)
    private String pwd;
    private Integer age;
    private String tel;
}

在这里插入图片描述


五、DML编程控制


DML:数据操纵语言

1. 主键生成策略(Insert)


主键生成的策略有哪几种方式?(根据不同场景应用的id生成策略也不相同)

  • 日志:自增(1,2,3,4,……)
  • 购物订单:特殊规则(FQ23948AK3843)
  • 外卖单:关联地区日期等信息(10 04 20200314 34 91)
  • 关系表:可省略id

1.1 主键生成策略控制(@TableId注解)


在实体类的主键属性上,使用属性注解@TableId,通过type属性设置主键生成策略。

type属性值参考IdType枚举值:(5种常用的生成策略,@Deprecated注解表示过时了)

  • AUTO:使用数据库的自增策略(mysql:auto_increment)控制id生成。
  • NONE:不设置id生成策略。(如果插入数据设置了id,那么它就用你设置的id,如果未指定id它默认用雪花算法生成id)
  • INPUT:用户手工输入id。
  • ASSIGN_ID:雪花算法生成id(可兼容数值型与字符串型)。
  • ASSIGN_UUID:以UUID生成算法作为id生成策略。(字符串)

示例:

@Data
public class User {
    //@TableId(type = IdType.AUTO)
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    @TableField(value = "password",select = false)
    private String pwd;
    private Integer age;
    private String tel;
}

雪花算法

雪花算法(snowflake)是推特开源的分布式ID生成算法,结果是一个long型的ID(一共64位)。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。

在这里插入图片描述


1.2 全局策略配置


如果某个类的主键不想使用全局配置的雪花算法,只需在该主键上配置@TableId的生成策略即可。

mybatis-plus:
  global-config:
    db-config:
      #id生成策略全局配置	
      id-type: assign_id
      # 表名前缀全局配置
      table-prefix: tb_

2. 批量操作(select、delete操作)


批量查询selectBatchIds、批量删除deleteBatchIds

2.1 按照主键批量删除多条记录

//用list集合存储要删除的主键id
List<Long> list = new ArrayList<>();
list.add(1402551342481838081L);
list.add(1402553134049501186L);
list.add(1402553619611430913L);
//批量删除
userMapper.deleteBatchIds(list);

2.2 根据主键批量查询多条记录

//批量查询
userMapper.selectBatchIds(Arrays.asList(1L,3L,4L));

3. 逻辑删除(Delect、Update操作)


在实际环境中,如果想删除一条数据,是否会真的从数据库中删除该条数据?

  • 物理删除 : 将数据直接从数据库中干掉。

  • 逻辑删除:为数据设置是否可用状态字段,删除时设置状态字段为不可用状态,但数据仍保留在数据库中。

逻辑删除快速入门

1、为数据库表添加逻辑删除字段。(设置默认值0,长度1,int类型)

在这里插入图片描述
在这里插入图片描述

2、在实体类中添加对应字段,并用@TableLogic注解配置当前字段为逻辑删除标记字,。

@Data
public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;

    //逻辑删除字段,标记当前记录是否被删除  1:删除  0:未删
    @TableLogic(value = "0",delval = "1")
    private Integer isDeleted;
}

3、开启mp驼峰映射(mp默认字段开启)

mybatis-plus:
 configuration:
  # 开启驼峰映射
  map-underscore-to-case: true

4、执行删除操作

@SpringBootTest
public class UserMapperLogicDeleteTest {

    @Autowired
    private UserMapper userMapper;

    @Test //junit5
    public void testLogicDelete() {
        int count = userMapper.deleteById(1619522751700262920L);
        if (count>0){
            System.out.println("删除成功");
        }
    }
}

在这里插入图片描述

执行逻辑删除前的表数据:

在这里插入图片描述

执行逻辑删除后的表数据:

在这里插入图片描述


注意:逻辑删除的本质其实是修改操作。如果加了逻辑删除字段,查询数据时也会自动带上逻辑删除字段。

在这里插入图片描述


扩展:逻辑删除全局配置

1、注掉实体类中逻辑删除注解

在这里插入图片描述


2、在yml中配置逻辑删除

mybatis-plus:
  global-config:
    db-config:
      table-prefix: tbl_
      # 逻辑删除字段名
      logic-delete-field: deleted
      # 逻辑删除字面值:未删除为0
      logic-not-delete-value: 0
      # 逻辑删除字面值:删除为1
      logic-delete-value: 1

在这里插入图片描述


3、测试

在这里插入图片描述

执行逻辑删除前的表数据:

在这里插入图片描述

执行逻辑删除后的表数据:

在这里插入图片描述


4. 乐观锁(Update操作)


乐观锁、悲观锁详解:https://blog.csdn.net/qq_34337272/article/details/81072874

1、在user表中添加一个锁标记字段:

在这里插入图片描述


2、实体类中添加对应属性,并配置当前属性为乐观锁标记字段

@Data
public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;

    @Version
    private Integer version;

    private Integer isDeleted;
}

在这里插入图片描述


3、配置乐观锁拦截器,实现锁机制对应的动态SQL语句拼装

package com.baidou.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MpConfig {
    @Bean
    public MybatisPlusInterceptor mpInterceptor() {
        //定义Mp拦截器
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
        
        //分页插件
        //...

        //乐观锁插件
        mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        
        return mpInterceptor;
    }
}

4、测试,使用乐观锁机制在修改前必须先获取到对应数据的verion才能正常进行

@Test
public void testUpdate() {
    // 通常在开发中先查询(有版本),后更新
    User user1 = userMapper.selectById(1L);
    User user2 = userMapper.selectById(1L);

    user1.setName("SpringCloud");
    user2.setName("Nacos");

    // 模拟并发修改
    userMapper.updateById(user1);
    userMapper.updateById(user2);
}

在这里插入图片描述
在这里插入图片描述


5. 字段自动填充


在开发中有些值是固定的(比如 创建时间、修改时间、创建人、修改人巴拉巴拉),而每次执行相关操作时都需要手动set,而mp提供了自动填充功能,不用手动封装那些数据了。

字段填充快速入门:

1、给user表添加两个字段create_time、update_time:

在这里插入图片描述

2、在实体类中需要填充的字段上通过@TableField注解的fill属性设置填充的时机

@Data
public class User {
    private Long id;
    private String name;
    private String password;
    private Integer age;
    private String tel;

    @Version
    private Integer version;

    @TableField(fill = FieldFill.INSERT) //新增的时候进行字段填充
    private LocalDateTime createTime;
    @TableField(fill = FieldFill.INSERT_UPDATE) //新增或修改的时候进行字段填充
    private LocalDateTime updateTime;

    private Integer isDeleted;
}

在这里插入图片描述

3、编写一个配置类实现MetaObjectHandler接口

package com.baidou.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;

// 重新MetaObjectHandler接口的字段自动填充时机方法

@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    // 新增的自动填充
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill ....");
        //方式1
        //this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); 
        //this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());

         //方式2
        //setFieldValByName("createTime",LocalDateTime.now(),metaObject);
        //setFieldValByName("updateTIme",LocalDateTime.now(),metaObject);
        
        //方式3
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime",LocalDateTime.now());  
    }

    // 修改的自动填充
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("start update fill ....");
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

4、测试

① 测试新增:

@Test
public void testInsert() {
    User user = new User();
    user.setName("王强");
    user.setAge(23);
    user.setPassword("233333");
    user.setTel("13121341234");
    int num = userMapper.insert(user);
    System.out.println("行数:" + num);
    System.out.println("id:" + user.getId());//id:1643892200968327170 主键自动返回
}

在这里插入图片描述

② 测试修改:

@Test //动态sql
public void testUpdate() {
    User user = new User();
    user.setId(1643892200968327170L);
    user.setName("eureka");
    int num = userMapper.updateById(user);
}

在这里插入图片描述


六、代码生成器


使用代码生成器好处:通过表,快速生成对应的实体类、mapper、service、controller代码(会有点小坑)

1、创建一个springboot基础工程

在这里插入图片描述

2、导入mp代码生成器相关依赖:

<!--代码生成器-->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.4.1</version>
</dependency>

<!--velocity模板引擎-->
<dependency>
    <groupId>org.apache.velocity</groupId>
    <artifactId>velocity-engine-core</artifactId>
    <version>2.3</version>
</dependency>

3、编写代码生成器类

package com.baidou.util;

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;

/**
 * 代码生成器
 */
public class CodeGenerator {
    public static void main(String[] args) {
        //1.获取代码生成器的对象
        AutoGenerator autoGenerator = new AutoGenerator();

        //设置数据库相关配置
        DataSourceConfig dataSource = new DataSourceConfig();
        dataSource.setDriverName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mp_db?useSSL=false&serverTimezone=UTC");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        autoGenerator.setDataSource(dataSource);

        //设置全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        String projectName = "mp04_test"; //工程名
        globalConfig.setOutputDir(System.getProperty("user.dir") + "/" + projectName + "/src/main/java");    //设置代码生成位置
        globalConfig.setOpen(false);    //设置生成完毕后是否打开生成代码所在的目录
        globalConfig.setAuthor("白豆五");    //设置作者
        globalConfig.setFileOverride(true);     //设置是否覆盖原始生成的文件
        //globalConfig.setMapperName("%sDao");    //设置数据层接口名,%s为占位符,指代模块名称
        globalConfig.setIdType(IdType.ASSIGN_ID);   //设置Id生成策略
        autoGenerator.setGlobalConfig(globalConfig);

        //设置包名相关配置
        PackageConfig packageInfo = new PackageConfig();
        packageInfo.setParent("com.baidou");   //设置生成的包名,与代码所在位置不冲突,二者叠加组成完整路径
        //packageInfo.setEntity("pojo");    //设置实体类包名 默认是entity
        //packageInfo.setMapper("dao");   //设置数据层包名 默认是mapper
        autoGenerator.setPackageInfo(packageInfo);

        //策略设置
        StrategyConfig strategyConfig = new StrategyConfig();
        //strategyConfig.setInclude("tbl_user");  //设置对指定表进行代码生成,参数为可变参数,不设置的话就是全部表
        strategyConfig.setTablePrefix("tbl_");  //设置隐藏数据库表的前缀名称,模块名 = 数据库表名 - 前缀名  例如: User = tbl_user - tbl_
        strategyConfig.setRestControllerStyle(true);    //设置Controller是否启用Rest风格
        strategyConfig.setVersionFieldName("version");  //设置乐观锁字段名
        strategyConfig.setLogicDeleteFieldName("deleted");  //设置逻辑删除字段名
        strategyConfig.setEntityLombokModel(true);  //设置是否启用lombok
        autoGenerator.setStrategy(strategyConfig);

        //2.执行生成操作
        autoGenerator.execute();
    }
}

效果如下:

在这里插入图片描述


七、条件构造器Wrappers


通用格式:

Wrappers.<实体类>lambdaQuery().xxx
Wrappers.<实体类>lambdaUpdate().xxx

测试:

@Test
public void testWarppers() {
    // LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
    // wrapper.like(User::getName,"小");
    // List<User> users = userMapper.selectList(wrapper);

    // 使用wrapper简化上面的lambda写法
    List<User> userList = userMapper.selectList(Wrappers.<User>lambdaQuery().like(User::getName, "小"));
    userList.forEach(System.out::println);
}

在这里插入图片描述

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
MyBatis Plus 是一个基于 MyBatis 的增强工具,它简化了 MyBatis 的开发流程,提供了更多便捷的操作方式。下面是一些关于 MyBatis Plus 的笔记: 1. 引入依赖:在项目的 pom.xml 文件中,添加 MyBatis Plus 的依赖。可以参考官方文档获取最新的版本信息。 2. 配置数据源:在项目的配置文件中,配置数据库连接信息。可以使用 Spring Boot 的配置文件,也可以使用 MyBatis Plus 提供的配置类来配置数据源。 3. 定义实体类:创建实体类,并使用注解进行字段和表的映射关系的标记。可以使用 @TableName 注解标记表名,@TableId 注解标记主键,@TableField 注解标记字段等。 4. 编写 Mapper 接口:创建 Mapper 接口,并继承 BaseMapper 接口。无需编写 XML 文件,MyBatis Plus 会根据接口方法的命名规则自动生成 SQL。 5. 使用通用 CRUD 方法:MyBatis Plus 提供了一些通用的 CURD 方法,如 insert、update、delete、select 等,并支持分页查询和条件查询。 6. 高级查询功能:MyBatis Plus 还提供了一些高级查询功能,如动态 SQL、条件构造器、Wrapper 查询等。可以根据具体需求选择使用。 7. 分页查询:MyBatis Plus 支持分页查询,可以通过 PageHelper 来实现分页功能。可以在查询方法中传入 Page 对象,并在查询结果中获取分页相关信息。 8. 自动填充功能:MyBatis Plus 支持自动填充功能,可以在实体类中定义字段,使用注解 @TableField(fill = FieldFill.INSERT) 标记需要自动填充的字段。 9. 乐观锁功能:MyBatis Plus 支持乐观锁功能,可以在实体类中定义字段,使用注解 @Version 标记乐观锁字段。在更新操作时,会自动判断版本号是否一致。 以上是一些关于 MyBatis Plus 的笔记,希望对你有帮助!如果有更多问题,可以继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白豆五

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值