MyBatisPlus学习笔记

MyBatisPlus学习笔记

一、MybatisPlus概述

1.1、简介

MyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,简化开发、提高效率而生。
MyBatisPlus学习笔记_第1张图片

1.2、特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本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.3、快速入门

mybatis-plus写的sql与方法

步骤:

  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)
);
DELETE FROM user;

INSERT INTO user (id, name, age, email) VALUES
                  (1, 'Jone', 18, '[email protected]'),
                  (2, 'Jack', 20, '[email protected]'),
                  (3, 'Tom', 28, '[email protected]'),
                  (4, 'Sandy', 21, '[email protected]'),
                  (5, 'Billie', 24, '[email protected]');
---- 真实开发中,version(乐观锁)、delete(逻辑删除)、gmt_create等
  1. 编写项目,初始化项目!使用Springboot初始化!
  2. 导入相关依赖
 
        <dependency>
	        <groupId>com.baomidougroupId>
	        <artifactId>mybatis-plus-boot-starterartifactId>
	        <version>最新版本version>
    	dependency>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.32version>
        dependency>

        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>

说明:使用mybatis-plus可以节省大量打啊代码,尽量不用同时导入mybatis和mybatis-plus!(可能会冲突)

  1. 数据库连接配置
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

#Mysql8版本需要在url上单独配置时区(serverTimezone=Asia/Shanghai),同时两者的驱动也是有差异的
  1. 使用了Mybatis-plus之后
    • 编写pojo

    • 创建mapper接口

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


// 在对应的Mapper接口上面继承基本的类BaseMapper
    @Mapper
//@Repository //代表是Mapper层即可
public interface UserMapper extends BaseMapper<User> {
    //所有的crud已基本完成了
    //不用需要像之前配置大量文件了
}

注意点:我们需要再主启动类上去扫描我们的mapper包下的所有接口

@MapperScan("com.yjr.springboot005mybatis_plus.mapper")

测试

@SpringBootTest
class Springboot005MybatisPlusApplicationTests {
//    继承了BaseMapper,所有的方法都来自自己的父类,我们可以编写自己的拓展方法。
    @Autowired
    private UserMapper userMapper;
    @Test
    void contextLoads() {
        //参数是一个Wrapper,条件构造器,这里不用写写为null
        //查询所有的用户
        List<User> users = userMapper.selectList(null);
        for (User user : users) {
            System.out.println(user);
        }
    }
}

结果
MyBatisPlus学习笔记_第2张图片

二、配置日志

2.1、日志配置

配置日志

# 配置日志--控制台输出
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

MyBatisPlus学习笔记_第3张图片

  1. insert插入
 //测试插入
    @Test
    public void insert(){
        User user=new User();
        //mybatis-plus会自动生成id
        user.setAge(3);
        user.setName("radan");
        user.setEmail("[email protected]");

        int insert = userMapper.insert(user);//insert是受影响的行数
        System.out.println(insert);
        System.out.println(user);//当执行insert方法时,mybatis-plus会自动生成id
    }

MyBatisPlus学习笔记_第4张图片

  1. 更新操作
    public void update(){
        User user=new User();
//        user.setAge(3);
        user.setId(4l);
//        user.setName("radan");
        user.setEmail("[email protected]");
        //注意:updateById 但是参数是一个对像!重点:通过条件就会拼接sql
        // UPDATE user SET name=?, age=?, email=? WHERE id=?
        //     UPDATE user SET email=? WHERE id=?
        int i = userMapper.updateById(user);//受影响的行数
        System.out.println(i);
    }

在这里插入图片描述

2.2、主键生成策略

对应数据库中的组件 (UUID,自增id,雪花算法,redis生成)
默认ASSIGN_ID全局唯一策略

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

主键自增

  1. 实体类字段上添加注解 @TableId(type = IdType.AUTO)
  2. 数据库锁对应的字段必须是自增的

IdType 类其它的源码解释

  • AUTO(0) 数据库id自增
  • NONE(1) 不设置主键
  • INPUT(2) 手动输入,必须自己配置id
  • ASSIGN_ID(3) 雪花算法
  • ASSIGN_UUID(4); //全局 全局唯一id uuid

2.3、 自动填充(时间操作)

代码级别操作

  1. 创建create_time和update_time字段
  2. 实体类属性上需要添加注解
 //字段添加填充内容
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(fill = FieldFill.UPDATE)

    private Date updateTime;
  1. 编写处理器来处理
@Component  //一定不要忘记将处理器加到IOC容器当中
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {

    //插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("插入填充");
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);

    }
    //更新时的填充策略
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("更新填充");
        this.setFieldValByName("updateTime",new Date(),metaObject);

    }
}

2.4、乐观锁

乐观锁:十分乐观,认为不会出现问题。无论干什么不去上锁!如果出现了问题,再次更新值测试。
悲观锁:无论干什么都会上锁,然后再去操作

乐观锁实现方式:

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

配置乐观锁的实现步骤:

  1. 在数据库中对应的表中建立version字段
  2. 在实体类的字段上加上@Version注解
    注意:
    • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
    • 整数类型下 newVersion = oldVersion + 1
    • newVersion 会回写到 entity 中
    • 仅支持 updateById(id) 与 update(entity, wrapper) 方法
    • 在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
  3. 编写配置类
@Configuration  //标明这是一个配置类
@ComponentScan("com.yjr.springboot005mybatis_plus.mapper") //指定扫描的包
public class MybatisPlusConfig {
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
}

  1. 编写测试类
    @Test
    public void testOptimisticLockerInterceptor(){
        //查询指定用户
        User user = userMapper.selectById(2L);
        user.setName("王冬");
        //更新指定用户
        userMapper.updateById(user);
    }

测试
在这里插入图片描述

当oldVersion和newVersion信息不一致就会导致更新失败

2.5、查询数据

2.5.1、单个查询

// 1. 按照id进行单个用户的查询
User user = userMapper.selectById(1L);

2.5.2、多条件查询

//  3. 多条件查询之一:使用 map 操作
        HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("id",1l);
        hashMap.put("name","radan");
        List<User> users = userMapper.selectByMap(hashMap);

2.5.3、批量查询

//  2. 查询批量用户  前三个用户   SELECT id,name,age,email,version,create_time,update_time FROM user WHERE id IN ( ? , ? , ? )
        for (User u1 : userMapper.selectBatchIds(Arrays.asList(1, 2, 3))) {
            System.out.println(u1);
        }

2.5.3、分页查询

  1. 原始的limit进行分页
  2. PageHelper第三方插件
  3. Mybatis-plus也内置了分页插件

mybatis-plus中的使用分页插件的步骤:

  1. 配置拦截器即可
		  /**
         * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
         */
   @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
      
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.H2));
        return interceptor;
    }
  1. 直接使用Page对象即可
    @Test
    public void  pageLimit(){
        //参数一(当前页)  参数二:页面大小
        Page<User> objectPage = new Page<>(2,5);
        userMapper.selectPage(objectPage,null);
        List<User> records = objectPage.getRecords();//objectPage.getRecords()得到分页后的所有记录
        for (User user : records) {
            System.out.println(user);
        }
        System.out.println("当前的记录总数:"+objectPage.getTotal());//得到当前的记录总数
        System.out.println("当前的页数:"+objectPage.getCurrent());
    }

2.6、删除操作

  1. 根据ID删除记录
//通过id进行删除
int result = userMapper.deleteById(1691640078306185217L);  //返回值为受影响的行数
  1. 批量删除
 //批量删除
int batchIds = userMapper.deleteBatchIds(Arrays.asList(1, 2, 3));
  1. 多条件删除
//多条件删除方式之一,map
HashMap<String,Object> map=new HashMap<>();
map.put("name","jom");
int i = userMapper.deleteByMap(map);

逻辑删除:从数据库中并没有移除,而是通过一个变量来让他失效!deleteState=0或1

物理删除:从数据库中直接移除
管理员可以查看到被删除的记录!防止数据的丢失,类似于回收站

逻辑删除的使用步骤

  1. 在YML中配置
#逻辑删除组件
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)

2 .在实体类字段上加上@TableLogic注解

	@TableLogic  //逻辑删除注解
    private Integer deleted;

在这里插入图片描述
在查询的时候会自动过滤掉deleted为1的字段

常见问题

  • 如何进行插入操作
    • 字段在数据库定义默认值(推荐)
    • insert 前自己 set 值
    • 使用 自动填充功能

三、性能分析插件

Mybatis-Plus提供共性能分析插件,如果超这个时间就会停止运行!
作用:性能分析拦截器,用于输出每条 SQL 语句及其执行时间
该功能依赖 p6spy 组件,完美的输出打印 SQL 及执行时长 3.1.0 以上版本

  1. 导入p6spy依赖
<dependency>
  <groupId>p6spygroupId>
  <artifactId>p6spyartifactId>
  <version>最新版本version>
dependency>

  1. application.yml配置
spring:
  # 数据源
  datasource:
    username: root
    password: 123456
    # GMT%2B8:GMT+8 格林尼治东八时区
    url: jdbc:p6spy:mysql://localhost:3306/mybatis_plus?useSSL=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8
    driver-class-name: com.p6spy.engine.spy.P6SpyDriver

  1. spy.properties 配置
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
#3.2.1以下使用或者不配置
#modulelist=com.p6spy.engine.logging.P6LogFactory,com.p6spy.engine.outage.P6OutageFactory
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
# 使用日志系统记录 sql
#appender=com.p6spy.engine.spy.appender.Slf4JLogger
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 实际驱动可多个
#driverlist=org.h2.Driver
# 是否开启慢SQL记录
outagedetection=true
#SQL记录标准 2outagedetectioninterval=2

测试结果

在这里插入图片描述

四、条件构造器Wrapper

复杂的sql就可以利用Warpper进行实现

4.1、Wrapper查询

  1. 查询name不为空的用户,并且邮箱不为空的数据,年龄大于等于12的
 @Test
    public void test(){
        //查询name不为空的用户,并且邮箱不为空的数据,年龄大于等于12的
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name");
        wrapper.isNotNull("email");  //name和email不为空
        wrapper.ge("age",12);  //age>=12
        for (User user : userMapper.selectList(wrapper)) {
            System.out.println(user);
        }
    }
    //SELECT * FROM user WHERE deleted=0 AND (name IS NOT NULL AND email IS NOT NULL AND age >= 12)
  1. 查询名字为radan的数据
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","Tom");
        userMapper.selectOne(wrapper);       //查询一个数据,出现多个数据会报错的
        //SELECT * FROM user WHERE deleted=0 AND (name = 'Tom')

注意:查询一个数据,查询多个数据结果使用list 或者 map

  1. 查询age在(12,20)之间的用户数
    @Test
    public void test12(){
        //查询age在(12,20)之间的用户数  
        //SELECT COUNT( * ) AS total FROM user WHERE deleted=0 AND (age BETWEEN ? AND ?)
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",12,20);
        Long aLong = userMapper.selectCount(wrapper);//selectCount查询结果数
        System.out.println(aLong);
    }
  1. 模糊查询
 public void test3(){
        //模糊查询
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //like==>%e%,  likeLeft==>%t(末尾有t)   likeRight==>t%(开头有t)
        wrapper.like("name","e")
                .likeRight("email","t");
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        for (Map<String, Object> map : maps) {
            System.out.println(map);
        }
        // SELECT * FROM user WHERE deleted=0 AND (name LIKE '%e%' AND email LIKE 't%')
    }
  1. 子查询
 public void test6(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        // id在子查询中查出
        wrapper.inSql("id","select id from user where id< 3");
        for (User user : userMapper.selectList(wrapper)) {
            System.out.println(user);
        }
        //SELECT * FROM user WHERE deleted=0 AND (id IN (select id from user where id< 3))
    }

4.2、 排序

@Test
    public void test7(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
//        wrapper.orderByAsc("id");//通过id升序排序
        wrapper.orderByDesc("id");//通过id降序排序
        //SELECT * FROM user WHERE deleted=0 ORDER BY id DESC
        for (User user : userMapper.selectList(wrapper)) {
            System.out.println(user);
        }

    }

五、代码生成器

适用版本:mybatis-plus-generator 3.5.1 及其以上版本,对历史版本不兼容!
MyBatis-Plus 的代码生成器可以生成 Entity、Mapper、Mapper XML、Service、Controller 模块代码。

5.1、依赖导入

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

        
        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-boot-starterartifactId>
            <version>3.5.3.2version>
        dependency>

        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.32version>
        dependency>

        
        <dependency>
            <groupId>org.projectlombokgroupId>
            <artifactId>lombokartifactId>
            <optional>trueoptional>
        dependency>
        
        
        <dependency>
            <groupId>com.baomidougroupId>
            <artifactId>mybatis-plus-generatorartifactId>
            <version>3.5.1version>
        dependency>
        
        <dependency>
            <groupId>org.apache.velocitygroupId>
            <artifactId>velocity-engine-coreartifactId>
            <version>2.3version>
        dependency>
        
        <dependency>
            <groupId>org.freemarkergroupId>
            <artifactId>freemarkerartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>

5.2、配置文件


server.port=8088
spring.profiles.active=dev

##数据库连接配置
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plue?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

5.3、代码生成类

package com.yjr;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


/**
 * @author radan
 * @Description
 * @date 2023/8/17 17:51
 */

public class PracticeApplication {
    public static void main(String[] args) {
        List<String> tables = new ArrayList<>();
        tables.add("user");  //可以给tables添加多个表名


        FastAutoGenerator.create("jdbc:mysql://localhost:3306/mybatis_plue","root","123456")
                .globalConfig(builder -> {
                    builder.author("radan")               //作者
                            .outputDir(System.getProperty("user.dir")+"\\src\\main\\java")    //输出路径(写到java目录)
//                            .enableSwagger()           //开启swagger
                            .commentDate("yyyy-MM-dd")
                            .disableOpenDir()    //不打开文件管理
                            .fileOverride();            //开启覆盖之前生成的文件
                    

                })
                .packageConfig(builder -> {
                    builder.parent("com.yjr")
//                            .moduleName("practice")
                            .entity("pojo")
                            .service("service")
                            .serviceImpl("service.impl")
                            .controller("controller")
                            .mapper("mapper")
                            .xml("mapper")
                            .pathInfo(Collections.singletonMap(OutputFile.mapperXml,System.getProperty("user.dir")+"\\src\\main\\resources\\mapper"));
                })
                .strategyConfig(builder -> {
                    builder.addInclude(tables)
//                            .addTablePrefix("p_")//过滤表前缀
                            .serviceBuilder()
                            .formatServiceFileName("%sService")
                            .formatServiceImplFileName("%sServiceImpl")
                            .entityBuilder()
                            .enableLombok()
                            .logicDeleteColumnName("deleted")
                            .enableTableFieldAnnotation()
                            .controllerBuilder()
                            // 映射路径使用连字符格式,而不是驼峰
                            .enableHyphenStyle()
                            .formatFileName("%sController")
                            .enableRestStyle()
                            .mapperBuilder()
                            //生成通用的resultMap
                            .enableBaseResultMap()
                            .superClass(BaseMapper.class)
                            .formatMapperFileName("%sMapper")
                            .enableMapperAnnotation()
                            .formatXmlFileName("%sMapper");
                })
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();
    }

}

结果
MyBatisPlus学习笔记_第6张图片

你可能感兴趣的:(MyBatis,学习,笔记)