小菜鸟更新,MyBatisPlus学习笔记

本文详细介绍了MyBatisPlus的特性、快速开始、CRUD操作、主键生成策略、自动填充、乐观锁、分页查询、逻辑删除、条件构造器Wrapper的使用,并提供了代码生成器的配置和使用方法。MyBatisPlus作为MyBatis的增强工具,简化了Java开发中的数据库操作,通过Lambda表达式和强大的条件构造器,让代码更加简洁高效。
摘要由CSDN通过智能技术生成

本笔记学习资源:狂神说Javahttps://space.bilibili.com/95256449?from=search&seid=4500591325352457207
大家多多支持,共同进步!!笔记中有错请各位不吝赐教。

MyBatisPlus

了解

官网:https://mp.baomidou.com/

image-20200424162130200

特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

为什么学习MyBatisPlus

在MyBaits中,一些简单的SQL仍然需要手动编写,而使用了MyBatisPlus就可以帮我们省去简单的CRUD代码的编写过程。

快速开始

  1. 使用官方数据 建库,数据插入

    image-20200424170027296

  2. spring-boot构建项目,MyBatisPlus等依赖导入

    <!--新版-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.3.1.tmp</version>
    </dependency>
    <!--旧版-->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.0.5</version>
    </dependency>
    
  3. 数据库连接的相关配置

    spring:
      application:
        name: mybatis_plus
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: root
        password: 170312
        url: jdbc:mysql://localhost:3306/mybatis_plus?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
    
  4. 编写User实体类

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
         
        private Long id;
        private String name;
        private Integer age;
        private String email;
    }
    
  5. 编写UserMapper接口

    从这里开始,Mybatis与MyBatisPlus的区别开始显现出来

    我们传统使用MyBatis的步骤是

    1. 编写Mapper接,定义方法
    2. 编写xxMapper.xml,通过SQL语句的编写实现接口中的方法

    使用MyBatisPlus则就是简简单单一步

    1. Mapper接口继承BaseMapper并传入泛型,你甚至方法都不用定义,普通的CRUD代码就已经为你实现了。
  6. 测试使用

    image-20200424171618943

注意点:

  • **在继承BaseMapper时需要传入 你所希望CRUD的对象类型 作为泛型参数。**例如上例中数据库中是User对象,所以我需要针对User创建一些简单的CRUD操作,只需要在UserMapper接口继承BaseMapper<User>。
  • 不要忘了使用@Mapper,或者@MapperScan

以上快速使用就结束了,有几个问题需要思考

  • 有哪些基本CRUD可以供我们使用?
  • 使用BaseMapper中的方法时的Wrapper是什么?

image-20200424173001853

通过简单浏览源码,和查看结构,简单的CRUD确实可以拿来即用,但是要想完全利用这个工具就需要了解Wapper这个类如何使用,基本上大部分的方法都需要这样一个参数,并且可看到泛型基本上每一个方法都使用到了,所以泛型参数一定的不能少的。

为了使我们能清楚看到MyBatisPlus自动生成的SQL我们可以进行日志配置,来输出生成的SQL语句

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl 

INSERT

先从插入开始,BaseMapper中只有一个方法与数据插入有关。insert(T t)

@Test
void insertUser() {
   

    User user = new User();
    user.setName("sakura");
    user.setAge(20);
    user.setEmail("843452233@qq.com");
    int result = userMapper.insert(user);
    System.out.println(result);
}

看的出来,我们并没有为主键Id 设置值,就直接进行了插入操作,结果如何呢?我们看看日志的输出

image-20200424224909308

即时我们没有为主键设置内容,他也会为我们自动生成一个哦,并且能够保证这个主键是全局唯一的

这就涉及到一个相关的知识点——主键生成策略

与之紧密联系的就是分布式全局唯一ID生成策略,推荐阅读https://www.jianshu.com/p/9d7ebe37215e

文章中介绍主要用到的ID生成策略有以下几种

  • 自增ID

  • UUID

  • 雪花算法(SnowFlake)——Twitter

  • Redis生成

而这里使用的正是雪花算法,雪花算法是生成的是一个 64位的2进制整数,即8个字节的整数,也就对应我们使用的数据类型Long,而这64位数据也并非随意组合。


雪花算法(知识补充)

以下借助文章中的图文

img

1位标识符始终是0,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。

41位时间戳:41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截 )得到的值,这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的。

10位机器标识码:可以部署在1024个节点,如果机器分机房(IDC)部署,这10位可以由 5位机房ID + 5位机器ID 组成。

12位序列:毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号

这样生成的id基本可以做到全球唯一。

了解完ID生成策略,我们回到主键生成策略,在主键id上使用@TableId(type=xxx)来更改使用其他主键生成策略。默认是使用IdType.NONE

IdType是一个枚举类,3.0.5版本提供了六种主键生成策略.

image-20200424233501102

最新版本3.3.0 使用ASSIGN_ID代替了ID_WORKER和ID_WORKER_STR,ASSIGN_UUID代替了UUID

image-20200425111200589

我们对这几种策略进行一一测试。

  • AUTO:数据库ID自增

    这个策略在我们数据库没有勾选主键Id自增选项时,是无法使用的。

  • INPUT:用户自定义填充

    这个就是你设置id是啥就是啥,但是需要程序员手动设置

    后面三个只有在插入对象时id为空才会自动填充,若已经手动设置,是无法生效的

  • ID_WORKER(过时)替换使用ASSIGN_ID

    这个就是使用的雪花算法,生成全球唯一ID,生成的ID是Long类型

  • UUID(过时)替换使用ASSIGN_UUID

    通过UUID生成全球唯一ID

  • ID_WORKER_STR(过时)替换使用ASSIGN_ID

    与ID_WORKER是一样的,它所生成的ID是String类型。

  • ASSIGN_ID(新版本更新)

    生成ID是number类型或String类型

UPDATE

更新数据,BaseMapper提供了两个方法update()updateById()

image-20200425082903317

在使用update方法时,需要我们传入一个条件Wrapper,如果填了null,会直接修改数据库中的所有数据,不要乱用噢

updateById(),也要求你的数据库中必须有ID这个字段,当然你在传入的User对象中不设置ID,在数据库中是无法匹配数据的,也就不能完成更新。

@Test
void updateUser() {
   

    User user = new User();
    user.setId(5L);
    user.setName("sakura");
    user.setAge(20);
    user.setEmail("3424307473@qq.com");
    int result = userMapper.updateById(user);
    System.out.println(result);
    
}

image-20200425084236217

image-20200425084346590

现在我们就可以看到MyBatisPlus强大的地方,它可以通过我们传入的实体类对象,来判断我们要修改什么,进而为我们生成动态SQL。

字段自动填充

在数据库中必然有一些时间相关地字段,阿里巴巴开发手册中关于数据库就有要求:

image-20200425084951459

必备字段:id、create_time、update_time,id前面我们提到了主键生成策略,而后面两个时间相关的字段也应该是由程序为我们自动生成,绝不是通过手动设置。这里就要用到自动填充

数据库修改(工作是禁止修改数据库,不推荐)

为createTime、updateTime两个字段设置默认值 CURREN_TIMESTAMP,并为updateTime字段勾选自动更新。

`create_time` datetime(6) DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
`update_time` datetime(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '修改时间',

image-20200425093058881

当然这种情况是可用的,但是不推荐使用。

程序填充(重点)

首先我们恢复数据库字段到初始状态

`create_time` datetime(6) NOT NULL COMMENT '创建时间',
`update_time` datetime(6) NOT NULL COMMENT '修改时间',

然后我们要在实体类中做ORM映射 (这里推荐使用JDK8的新版时间类LocalDateTime)

private LocalDateTime createTime;
private LocalDateTime updateTime;

现在我们要对需要自动填充的字段使用@TableField注解(这个注解简直是宝藏!)

源码中我们发现这个注解有一个fill属性是用于设置字段自动填充策略

image-20200425093842749

然后又能看到 有一个关于自动填充策略的枚举 FieldFill,默认的填充策略是DEFAULT,进入FieldFill来看看还有哪些填充策略

image-20200425094102810

  • Default 默认不处理
  • INSERT 插入时自动填充
  • UPDATE 更新时自动填充
  • INSERT_UPDATE 插入和更新时自动填充

这四个策略刚好满足我们的需求,createTime 只需要在插入时填充,updateTime在插入和更新时填充

@TableField(fill = FieldFill.INSERT)
private Date createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

修改完字段,按官方文档使用介绍我们还需要手动编写一个处理器并实现MetaObjectHandler接口,并重写insertFill、updateFill方法

基本框架:

@Slf4j
@Component // 一定要注册到容器
public class MyMetaObjectHandler implements MetaObjectHandler {
   

    @Override
    public void insertFill(MetaObject metaObject) {
   
        
    }

    @Override
    public void updateFill(MetaObject metaObject) {
   

    }
}

在3.0.5版本中使用this.setFieldByName(),来设置属性填充

setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject)

但是在更新到3.3.0+版本,这个方法过时了,采用this.strictInsertFill()strictUpdateFill()

strictInsertFill(MetaObject metaObject, String fieldName, Class<T> fieldType, Supplier<T> fieldVal)
    
strictUpdateFill(MetaObject metaObject, String fieldName, Class<T> fieldType, Object fieldVal)

明显后者定位属性要更加准确,要求我们设置自动填充属性的 属性名和类型

@Override
public void insertFill(MetaObject metaObject) {
   
    log.info("insertFill start==>");
    // 旧版本使用
    // this.setFieldValByName("createTime",LocalDateTime.now(),metaObject);
    // this.setFieldValByName("updateTime",LocalDateTime.now(),metaObject);
    
    // 新版本使用
    this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
    this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    log.info("insertFill end <==");
}

@Override
public void 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值