MyBatis-Plus:MyBatis-Plus的具体介绍与使用

我是 ABin-阿斌:写一生代码,创一世佳话,筑一揽芳华。 如果小伙伴们觉得我的文章有点 feel ,那就点个赞再走哦。
在这里插入图片描述

一、什么是 MyBatis-plus

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

二、MyBatis-plus与MyBatis有和不同

2.1、不同之处

MyBatis:

  • 简单易学: 没有任何的第三方依赖,比较轻量化。
  • 灵活: SQL 语句只需要我们写在 xml 中即可,便于我们的统一化管理和维护。不会对我们的应用层或者 DB 的现有设计附加不必要的影响。
  • 解除了我们SQL 与业务代码的耦合性: 通过提供的 DAL 层,将业务逻辑和数据访问逻辑进行一个有效的分离,从而提高了我们的一个可维护性。
  • 提供了对象关系映射标签: 支持对象关系组建维护
  • 提供了 xml 标签,支持编写动态 SQL: 我们可以直接编写动态 SQL

MyBatis-Plus:

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

三、快速入门:MyBatis-plus

3.1、创建数据表

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) );
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');

3.2、创建 SpringBoot 项目,导入相关依赖

注意:我们使用 MyBatis-plus 可以节省我们大量的代码,尽量不要同时导入 MyBatis 和 MyBatis-plus 的依赖,以免造成版本冲突。

<!-- 数据库驱动 --> 
<dependency> 
<groupId>mysql</groupId> 
<artifactId>mysql-connector-java</artifactId> 
</dependency> 
<!-- lombok --> 
<dependency> 
<groupId>org.projectlombok</groupId> 
<artifactId>lombok</artifactId> 
</dependency> 
<!-- mybatis-plus --> 
<!-- mybatis-plus 是自己开发,并非官方的! --> 
<dependency> 
<groupId>com.baomidou</groupId>
 <artifactId>mybatis-plus-boot-starter</artifactId> 
 <version>3.0.5</version> 
 </dependency>

3.3、配置连接数据库信息

# MySQL数据配置
# mysql 5 驱动不同 com.mysql.jdbc.Driver
# mysql 8 驱动不同com.mysql.cj.jdbc.Driver、需要增加时区的配置:serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/test1?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

3.4、相关类的创建

实体类:

@Data 
@AllArgsConstructor 
@NoArgsConstructor 
public class User { 
private Long id; 
private String name; 
private Integer age; 
private String email; 
}

Mapper接口

注意:别忘记在主启动类上去扫描我们的mapper包下的所有接口
代码:@MapperScan(“com.mangobin.mapper”)

/**
 * @author ABin-阿斌
 * @description
 * @date 2021/4/1
 */
// 在对应的Mapper上面继承基本的类 BaseMapper
@Repository //该注解表示当前是一个持久层
public interface UserMapper  extends BaseMapper<User> {

}

编写测试类

@SpringBootTest
@Slf4j
class MybatisPlus01ApplicationTests {

    @Autowired
    private UserMapper userMapper;

    /**
     * 数据查询测试
     */
    @Test
    void contextLoads() {
        //由于我们Mapper 接口继承了 BaseMapper,它里面会帮我们完成最基本的CRUD操作
        //而不需要我们去编写 SQL,除非有一些多表或复杂的业务时才需要我们自己去定义

        //查询所有用户数据
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }

测试结果

在这里插入图片描述

四、配置日志信息

  当我们执行程序的时候我们可以清晰的看到打印 SQL 语句的日志信息,这个在我们实际开发找 Bug 排错起到了很大的作用。

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

配置完成后的效果展示:

在这里插入图片描述

五、CRUD的具体操作

5.1、插入操作(Insert)
 /**
     * 数据插入测试
     */
    @Test
    public void testInsert() {
        User user = new User();
        user.setName("里西西");
        user.setAge(3);
        user.setEmail("2121212@qq.com");
        int result = userMapper.insert(user);
        //打印插入信息,查是否插入成功
        log.info("插入的条数为:" + result);
        //查看 Id 自增注解是否有效
        log.info("Id自增展示:" + user);
    }

在这里插入图片描述

5.2、更新操作
    /**
     * 数据更新测试
     */
    @Test
    public void testUpdate() {
        User user = new User();
        user.setId(1378265857087610884L);
        user.setName("栈北北");
        user.setAge(22);
        user.setEmail("6666212@qq.com");
        int result = userMapper.updateById(user);
        //打印插入信息,查是否插入成功
        log.info("修改的条数为:" + result);
    }

注意事项:

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

5.3、查询操作
/**
     * 根据 Id 查询数据
     */
    @Test
    public void testSelectById() {
        User user = userMapper.selectById(3L);
        log.info("查询到的数据为:" + user);
    }


    /**
     * 查询所有数据
     */
    @Test
    public void testAll() {
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 3, 5));
        users.forEach(System.out::println);
    }


    /**
     * 使用 Map 进行条件查询
     */
    @Test
    public void testSelectByMap() {
        HashMap<String, Object> map = new HashMap(16);
        map.put("name", "张三");
        map.put("age", 22);

        List<User> users = userMapper.selectByMap(map);
        users.forEach(System.out::println);
    }
5.4、分页查询操作

  在实际开发当中不管我们做的是什么项目,分页查询功能是我们不可避免要做的。常见的分页做法有: 原始的 limit 进行分页、pageHelper 第三方插件。当然,在 Mybatis-plus 当中也有它特有的分页功能。

实现思路:

  • 第一步:我们注入MyBatis-plus 分页插件
 /**
     * 分页插件
     *
     * @return
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
  • 第二步:编写测试类
 @Test
    public void testPage() {
        /**
         * 参数一:当前页
         * 参数二:页面大小
         */
        Page<User> page = new Page<>(1, 3);
        page.getRecords().forEach(System.out::println);
        userMapper.selectPage(page, null);
        System.out.println(page.getTotal());
    }
5.5、删除操作
 /**
     * 测试删除操作
     */
    @Test
    public void testDeleteById() {
        userMapper.deleteById(4L);
    }

    /**
     * 通过 Id 进行删除
     */
    @Test
    public void testDeleteBatchIds() {
        userMapper.deleteBatchIds(Arrays.asList(
                1L,
                2L,
                6L));
    }

    /**
     * 通过 Map 集合进行删除
     */
    @Test
    public void testDeleteByMap() {
        HashMap<String, Object> map = new HashMap<>(16);
        map.put("name", "小东东");
        map.put("age", 22);
        userMapper.deleteByMap(map);

    }
5.6、逻辑删除

什么是逻辑删除

  • 一般我们删除从某种意义上可以分为两种:一种叫【物理删除】,一种叫【逻辑删除】。
  • 物理删除:我们一般指的是从数据库中直接删除,可直观看见的。
  • 逻辑删除:我们一般指的是:在数据库中我们并没有发现数据变动,而是通过一个变量来让它失效。比如:deleted = 0 或 deleted = 1

有什么作用

  • 不管我们做什么项目都会有一个后台管理系统,该系统一般用于我们处理数据和用户信息数据。那么,这么多的数据难免会有人开发人员进行删除,防止误删丢失有效数据,我们管理人员【权限配置】可以看到是删除该记录的人员是那个,从而有效进行恢复。

如何使用

  • 第一步:我们在 User 表中加入 deleted 字段用来做标识

注意:加入该字段时,设置默认值为 0(表示未执行) 1(表示:已执行逻辑删除)
在这里插入图片描述

  • 第二步:在实体类中加入该属性和注解

    /**
     * 逻辑删除标识
     */
    @TableLogic
    private Integer deleted;
  • 第三步:注入逻辑删除组件
    /**
     * 逻辑删除
     */
    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }
  • 第四步:在配置文件中加入【逻辑删除配置】
# 配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1 
mybatis-plus.global-config.db-config.logic-not-delete-value=0
  • 第五步:测试
 /**
     * 测试删除操作
     */
    @Test
    public void testDeleteById() {
        userMapper.deleteById(4L);
    }

    /**
     * 通过 Id 进行删除
     */
    @Test
    public void testDeleteBatchIds() {
        userMapper.deleteBatchIds(Arrays.asList(
                1L,
                2L,
                6L));
    }

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

查询测试

    /**
     * 查询所有数据
     */
    @Test
    public void testAll() {
        List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 3, 5));
        users.forEach(System.out::println);
    }

在这里插入图片描述

六、主键生成策略

什么是组件生成策略:具体可看这篇文章:什么是组件生成策略

雪花算法:(snowflake)

  • SnowflakeTwitter 开源的分布式 ID 生成算法,结果是一个 long 型的 ID其核心思想是: 使用 41bit 作为毫秒数,10bit 作为机器的 ID(5个 bit 是数据中心,5个 bit 的机器ID),12bit 作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位永远是0,可以保证几乎全球唯一性。
6.1、配置主键自增
  • 第一步:将数据表id字段设置成自增

在这里插入图片描述

  • 第二步:我们在实体类字段上加上注解

在这里插入图片描述
具体源码解析:

public enum IdType { 
AUTO(0), // 数据库id自增 
NONE(1), // 未设置主键 
INPUT(2), // 手动输入 
ID_WORKER(3), // 默认的全局唯一id 
UUID(4), // 全局唯一id uuid 
ID_WORKER_STR(5); //ID_WORKER 字符串表示法
 }

七、配置MySQL自动填充时间信息

  在我们实际开发当中,一般表中的时间字段是不需要我们手动去做修改,都是由自动化来进行完成

7.1、通过数据库的方式:
  • 第一步:在User 表中添加时间字段,且为自动更新
    • 将 create_time、update_time,类型选 datetime ,然后默认值设置【CURRENT_TIMESTAMP】
    • 在这里插入图片描述

第二步:在实体类中添加上这两个属性

private Date createTime; 
private Date updateTime;

第三步:我们再次测试插入操作,看看是否有变化

在这里插入图片描述

在这里插入图片描述

7.2、使用代码的方式:

第一步:我们去除刚刚在数据库中默认值的配置

在这里插入图片描述
第二步:在实体类属性上加上相应的注解

    /**
     * 创建时间
     */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    /**
     * 修改时间
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

第三步:编写处理器来对该注解进行处理

/**
 * @author ABin-阿斌
 * @description 时间自动更新处理器
 * @date 2021/4/3
 */
@Slf4j
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    /**
     * 输入插入时的时间填充
     *
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("数据正在插入中.......");
        /**
         * @param fieldName  Java bean属性名称
         * @param fieldVal   java bean 属性值
         * @param metaObject 元对象参数
         */
        this.setFieldValByName("createTime", new Date(), metaObject);
        this.setFieldValByName("updateTime", new Date(), metaObject);
    }

    /**
     * 数据修改时的数据填充
     *
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("数据正在修改中......");
        this.setFieldValByName("updateTime", new Date(), metaObject);

    }
}

第四步:测试我们的插入与更新,查看是否生效

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

八、乐观锁与悲观锁

8.1 什么是乐观锁与悲观锁
8.2、如何使用乐观锁

具体的实现思路:

  • 取出记录时,获取当前 version(版本号)
  • 更新时,带上这个 version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果 version 不对,就更新失败
乐观锁:1、先查询,获得版本号 version = 1 
-- A 
update user set name = "张三", version = version + 1 
where id = 2 and version = 1 
-- B 线程抢先完成,这个时候 version = 2,会导致 A 修改失败! 
update user set name = "张三", version = version + 1 
where id = 2 and version = 1

第一步:我们在数据库中添加 version(版本号)字段

在这里插入图片描述
第二步:在实体类中添加【版本号】属性和注解

    /**
     * 版本号:乐观锁
     */
    @Version
    private Integer version;

第三步:注入乐观锁的插件

/**
 * @author ABin-阿斌
 * @description Mybatis-Plus配置类
 * @date 2021/4/3
 */
@MapperScan("com.mangobin.mapper")
@EnableTransactionManagement
@Configuration
public class MybatisPlusConfig {

    /**
     * 注入乐观锁插件
     *
     * @return
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }

第四步:编写乐观锁测试类

/**
     * 测试乐观锁的版本号机制是否生效
     */
    @Test
    public void testOptimisticLocker() {
        User user = userMapper.selectById(3L);
        user.setName("李四");
        user.setAge(22);
        userMapper.updateById(user);
    }

    /**
     * 乐观锁失效:多线程并发下的修改操作
     */
    @Test
    public void testConcurrentModification() {
        User user = userMapper.selectById(3L);
        user.setName("马到成功");
        user.setAge(22);

        User user2 = userMapper.selectById(3L);
        user2.setAge(25);
        user2.setName("青云直上");
        userMapper.updateById(user2);
        userMapper.updateById(user);
    }

在这里插入图片描述

SQL性能分析插件

性能分析插件是什么
  • 在我们日常开发工作当中,避免不了查看当前程序所执行的 SQL 语句,便于程序员排忧解难。

  • MyBatis-plus 提供了两种方式,用于输出每条 SQL 语句及其执行时间,针对执行较长时间的 SQL 可以停止运行,有助于发现问题。

  • 注意: 这两种方式只适用于开发环境和测试环境,不建议生产环境使用,因为在分析SQL时会增大我们的一个性能消耗。

如何使用
  • 第一步:导入插件
    /**
     * SQL执行效率插件
     *  @Profile设置: dev test 环境开启,保证我们的效率
     */
    @Bean
    @Profile({"dev", "test"})
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        performanceInterceptor.setMaxTime(1000);
        // ms设置sql执行的最大时间,如果超过了则不 执行
        performanceInterceptor.setFormat(true);
        // 是否格式化代码
        return performanceInterceptor;
    }
  • 第二步:设置环境为dev,可以在yml如下配置,或者直接测试类中也可以设置。
# 配置开发环境:dev
spring.profiles.active=dev

在这里插入图片描述

  • 第三步:编写测试类,查看插件是否生效
    /**
     * 数据查询测试
     */
    @Test
    void contextLoads() {
        //由于我们Mapper 接口继承了 BaseMapper,它里面会帮我们完成最基本的CRUD操作
        //而不需要我们去编写 SQL,除非有一些多表或复杂的业务时才需要我们自己去定义

        //查询所有用户数据
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::println);
    }

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

十、条件构造器

什么是条件构造器
  • 条件构造器可谓是MP的一大巨作了,大大提高了我们的开发效率。
  • 接口方法的参数中,会出现各种 Wrapper,比如 queryWrapper、updateWrapper 等。Wrapper 的作用就是用于定义各种各样的条件(where)。所以不管是查询、更新、删除都会用到 Wrapper。
如何使用
  • 代码演示:这里只举例比较常用的几种,更多的演示可以参考【官方文档】
package com.mangobin;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mangobin.entity.User;
import com.mangobin.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
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 ABin-阿斌
 * @description
 * @date 2021/4/5
 */
@SpringBootTest
@Slf4j
public class WrapperTest {

    @Autowired
    private UserMapper userMapper;


    /**
     * isNotNull(不为空)、ge(大于等于)、 eq(等于) 的具体使用
     * 查询用户名、邮箱不为空的用户,且年龄 >= 12的
     */
    @Test
    void contextLoads() {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
//        userQueryWrapper.isNotNull("name")
//                .isNotNull("age")
//                .ge("age", 12);
//        List<User> users = userMapper.selectList(userQueryWrapper);
//        users.forEach(System.out::println);
        userQueryWrapper.eq("name", "青云直上");
        userMapper.selectOne(userQueryWrapper);
        System.out.println(userQueryWrapper);
    }

    /**
     * Between(区间范围)、Like(模糊查询:左右)、OrderBy(排序)
     */
    @Test
    void test02() {
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        //区间条件
//        userQueryWrapper.between("age", 20, 30);
//        userMapper.selectCount(userQueryWrapper);

        //模糊查询
       /* userQueryWrapper.notLike("name", "e")
                .likeRight("email", "t");
        List<Map<String, Object>> maps = userMapper.selectMaps(userQueryWrapper);
        maps.forEach(System.out::println);*/

       //通过子查询进行查询
        userQueryWrapper.inSql("id", "select id from user where id <= 3");
        List<User> users = userMapper.selectList(userQueryWrapper);
        users.forEach(System.out::println);


        //排序
        //通过 Id 进行升序查询
//        userQueryWrapper.orderByAsc("id");
//        List<User> users = userMapper.selectList(userQueryWrapper);
//        users.forEach(System.out::println);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值