MyBatis-Plus——详解常用注解

哈喽!大家好,我是【一心同学】,一位上进心十足的【Java领域博主】!

✨【一心同学】的写作风格:喜欢用【通俗易懂】的文笔去讲解每一个知识点,而不喜欢用【高大上】的官方陈述。

✨【一心同学】博客的领域是【面向后端技术】的学习,未来会持续更新更多的【后端技术】以及【学习心得】。

✨如果有对【后端技术】感兴趣的【小可爱】,欢迎关注一心同学

❤️❤️❤️感谢各位大可爱小可爱!❤️❤️❤️ 


目录

前言

一、@TableName

1.1  介绍

1.2  使用

二、@TableId

2.1  介绍

2.2   AUTO属性

2.3  INPUT属性

2.4  AUTO与INPUT对比

三、@TableField

3.1  介绍

3.2   普通属性

3.3  自动填充属性

四、乐观锁

4.1  介绍

4.2  注意事项

4.3  实现乐观锁

4.4  测试

五、逻辑删除

5.1  介绍

5.2  实现逻辑删除

5.3  测试

小结


 

前言

本篇博客将详细介绍MyBatis-Plus中的常用注解以及其注意事项,并会对其常用的属性进行举例说明,而不常用的属性大家可根据描述信息进行了解。

一、@TableName

1.1  介绍

  • 描述:表名注解,映射数据库的表名
  • 使用位置:实体类

属性值
属性 类型 必须指定 默认值 描述
value String "" 表名
schema String "" schema
keepGlobalPrefix boolean false 是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)
resultMap String "" xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)
autoResultMap boolean false 是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)
excludeProperty String[] {} 需要排除的属性名 @since 3.3.1

1.2  使用

使用场景:当我们的实体类名跟我们的数据库表名不一致时,可根据@TableName来指定数据库表名。

例如:

我们的数据库表名是叫做person,但我们的Java实体类中却叫做User

MyBatis-Plus——详解常用注解_第1张图片

MyBatis-Plus——详解常用注解_第2张图片

解决映射冲突

添加注解@TableName(value = "person")

package com.yixin.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "person")
public class User {
    
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

二、@TableId

2.1  介绍

  • 描述:主键注解
  • 使用位置:实体类主键字段

属性值
属性 类型 必须指定 默认值 描述
value String "" 主键字段名
type Enum IdType.NONE 指定主键类型

IdType属性
描述
AUTO 数据库自增
NONE 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)雪花算法实现
INPUT 需要开发者手动赋值
ASSIGN_ID MP 分配 ID,Long、Integer、String
ASSIGN_UUID 分配 UUID,Strinig

 我们讲解在IdType中两个最常见的属性:AUTOINPUT

2.2   AUTO属性

  • 使用前提:需要在数据库中将主键设置为自增
  • 生成ID算法:【雪花算法】,基本可以保证全球唯一ID值。
  • 特点:生成的ID值在原来的ID基础上自增,并且会将ID值回填到我们的Java对象中。

注意:对主键使用了AUTO,那么我们自行注入的ID值将会被自动生成的ID覆盖

代码演示:

package com.yixin.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

测试:

我们在插入时自定义ID值

    @Test
    void test4() {

        // 我们没有自定义id,它会帮我们自动生成id
      Person person =new Person();
      person.setId(2L);
      person.setName("一心同学");
      person.setAge(18);
      person.setEmail("[email protected]");

      int result=personMapper.insert(person);

      System.out.println(result);// 受影响的行数

         System.out.println(person);//可以发现,id会自动回填
    }

结果:

发现1可以发现MP并没有采纳我们的ID值,因为其注入语句中根本就没有我们的主键id,而是选择用【雪花算法】自动生成的ID值。

发现2自动生成的ID值自动回填到我们的Java对象中了。

MyBatis-Plus——详解常用注解_第3张图片

2.3  INPUT属性

生成ID算法:【雪花算法】,基本可以保证全球唯一ID值。

特点开发者没有手动赋值,则数据库通过自增的方式给主键赋值,如果开发者手动赋值,则存入该值。

注意:并不会回填到我们的Java对象中。

代码演示:

package com.yixin.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    @TableId(type = IdType.INPUT)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}

(1)自定义ID测试

    @Test
    void test4() {

     //我们自定义ID,则会使用我们的ID,否则自动生成ID
      Person person =new Person();
      person.setId(5L);
      person.setName("一心同学2");
      person.setAge(18);
      person.setEmail("[email protected]");

      int result=personMapper.insert(person);

      System.out.println(result);// 受影响的行数

         System.out.println(person);
    }

结果:可以发现,MP是采用我们自定义的ID值的

MyBatis-Plus——详解常用注解_第4张图片

(2)不定义ID值测试

    @Test
    void test4() {

     //我们自定义ID,则会使用我们的ID,否则自动生成ID
      Person person =new Person();
      person.setName("一心同学3");
      person.setAge(18);
      person.setEmail("[email protected]");

      int result=personMapper.insert(person);

      System.out.println(result);// 受影响的行数

         System.out.println(person);//发现不会回填!
    }

结果:可以发现,当我们没有进行ID的定义时,MP将会通过自增的方式给主键赋值,并且不会将赋完的值注入到我们的Java对象。

 

MyBatis-Plus——详解常用注解_第5张图片

但在我们数据库中是有Id值的,只是没回填到Java对象而已。

MyBatis-Plus——详解常用注解_第6张图片

2.4  AUTO与INPUT对比

AUTO与INPUT对比
Type 算法 特点 是否覆盖自定义值 是否回填
AUTO 雪花算法 生成的ID值在原来的ID基础上自增
INPUT 雪花算法 开发者没有手动赋值,则数据库通过自增的方式给主键赋值,如果开发者手动赋值,则存入该值。

三、@TableField

3.1  介绍

描述:字段注解(非主键)

属性值
属性 类型 必须指定 默认值 描述
value String "" 数据库字段名
exist boolean true 是否为数据库表字段
condition String "" 字段 where 实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的 %s=#{%s},参考(opens new window)
update String "" 字段 update set 部分注入,例如:当在version字段上注解update="%s+1" 表示更新时会 set version=version+1 (该属性优先级高于 el 属性)
insertStrategy Enum FieldStrategy.DEFAULT 举例:NOT_NULL
insert into table_a(column) values (#{columnProperty})
updateStrategy Enum FieldStrategy.DEFAULT 举例:IGNORED
update table_a set column=#{columnProperty}
whereStrategy Enum FieldStrategy.DEFAULT 举例:NOT_EMPTY
where column=#{columnProperty}
fill Enum FieldFill.DEFAULT 字段自动填充策略
select boolean true 是否进行 select 查询
keepGlobalFormat boolean false 是否保持使用全局的 format 进行处理
jdbcType JdbcType JdbcType.UNDEFINED JDBC 类型 (该默认值不代表会按照该值生效)
typeHandler Class UnknownTypeHandler.class 类型处理器 (该默认值不代表会按照该值生效)
numericScale String "" 指定小数点后保留的位数

FieldStrategy 属性
描述
IGNORED 忽略判断
NOT_NULL 非 NULL 判断
NOT_EMPTY 非空判断(只对字符串类型字段,其他类型字段依然为非 NULL 判断)
DEFAULT 追随全局配置

FieldFill属性值
描述
DEFAULT 默认不处理
INSERT 插入时填充字段
UPDATE 更新时填充字段
INSERT_UPDATE 插入和更新时填充字段

 看到上面这么多属性,是不是突然就了,不要怕!【一心同学】在这里,对于上面的属性,在我们开发中一些是不常用的,【一心同学】在这里用代码演示几个常见的属性,大家务必掌握。

3.2   普通属性

代码演示:

package com.yixin.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "person")
public class User {
    @TableId(type=IdType.AUTO)
    private Long id;

    // 当该字段名称与数据库名字不一致
    @TableField(value = "name")
    private String name;

    // 不查询该字段
    @TableField(select = false)
    private Integer age;

      // 是否为数据库表字段,设置为false,则插入时不会对其操作
    @TableField(exist = false)
    private String email;

    

}

3.3  自动填充属性

步骤一数据库增加两个属性,create_timeupdate_time。

MyBatis-Plus——详解常用注解_第7张图片

步骤二:实体类字段属性添加注解。

    // 第一次添加填充
    @TableField(fill= FieldFill.INSERT)
    private Date createTime;


    // 第一次添加的时候填充,但之后每次更新也会进行填充
    @TableField(fill=FieldFill.INSERT_UPDATE)
    private Date updateTime;

步骤三:编写处理器来处理这个注解

注意:在处理器类上方添加注解@Component!

 

package com.yixin.mybatis_plus.handler;

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.util.Date;

@Slf4j
@Component // 一定不要忘记把处理器加到IOC容器中!
public class MyMetaObjectHandler implements MetaObjectHandler {
    // 插入时的填充策略
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("start insert fill.....");
        // setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }

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

测试:

    @Test
    void test9() {

        // 我们没有自定义id,它会帮我们自动生成id
        User person =new User();
        person.setName("一心同学呀");
        person.setAge(20);
        person.setEmail("[email protected]");

        int result=personsMapper.insert(person);

        System.out.println(result);// 受影响的行数

        System.out.println(person);//可以发现,id会自动回填
    }

数据库

四、乐观锁

4.1  介绍

乐观锁 : 故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,再次更新值测试

悲观锁:故名思意十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!

乐观锁实现方式

取出记录时,获取当前 version

更新时,带上这个version

执行更新时, set version = newVersion where version = oldVersion

如果version不对,就更新失败

代码解释:

乐观锁:1、先查询,获得版本号 version = 1
-- A

update person set name = "yixin", version = version + 1
 where id = 2 and version = 1

-- B 线程抢先完成,这个时候 version = 2,会导致 A 修改失败!
update person set name = "yixin", version = version + 1 
where id = 2 and version = 1

4.2  注意事项

  • 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
  • 整数类型下 newVersion = oldVersion + 1
  • newVersion 会回写到 entity 中
  • 仅支持 updateById(id) 与 update(entity, wrapper) 方法
  • 在 update(entity, wrapper) 方法下, wrapper 不能复用

4.3  实现乐观锁

步骤一:给数据库中增加version字段!

MyBatis-Plus——详解常用注解_第8张图片

步骤二:实体类添加对应的字段。

package com.yixin.mybatis_plus.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
    private Integer age;
    private String email;
    
    @Version //乐观锁Version注解
    private Integer version;
}

步骤三:注册组件。

package com.yixin.mybatis_plus.config;

import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

// 扫描我们的 mapper 文件夹
@MapperScan("com.yixin.mybatis_plus.mapper")
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {

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


}

4.4  测试

(1)测试乐观锁成功情况

    @Test
    void testOptimisticLocker() {

        // 1、查询用户信息
       Person person=personMapper.selectById(1L);

        // 2、修改用户信息
        person.setName("一心同学");

        int result=personMapper.updateById(person);

        System.out.println(result);// 受影响的行数
    }

结果:可以发现MP会自动帮我们进行乐观锁判定。

并且每修改一次,version就会+1。

MyBatis-Plus——详解常用注解_第9张图片

(2)测试失败情况!多线程下!

    @Test
    void testOptimisticLocker2() {

        // 线程 1
        Person person=personMapper.selectById(3L);
        person.setName("一心同学在写博客");


        // 模拟另外一个线程执行了插队操作
        Person person2=personMapper.selectById(3L);
        person2.setName("一心同学在吃饭");

        personMapper.updateById(person2);

        int result=personMapper.updateById(person);// 如果没有乐观锁就会覆盖插队线程的值!

        System.out.println(result);// 受影响的行数
    }

数据库:

MyBatis-Plus——详解常用注解_第10张图片

也就是说我们的线程一没有执行成功



 

五、逻辑删除

5.1  介绍

物理删除 :从数据库中直接移除

逻辑删除 :再数据库中没有被移除,而是通过一个变量来让他失效! deleted = 0 => deleted = 1

管理员可以查看被删除的记录!防止数据的丢失,类似于回收站

5.2  实现逻辑删除

步骤一:在数据表中增加一个 deleted 字段。

 MyBatis-Plus——详解常用注解_第11张图片

步骤二:实体类中增加属性。

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

步骤三:配置。

(1)在自定义配置类中添加逻辑删除组件

package com.yixin.mybatis_plus.config;

import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

// 扫描我们的 mapper 文件夹
@MapperScan("com.yixin.mybatis_plus.mapper")
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {

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

    // 逻辑删除组件!
    @Bean
    public ISqlInjector sqlInjector() {
        return new LogicSqlInjector();
    }

}

(2)在application.properties添加配置

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

5.3  测试

    @Test
    void test6() {
        int result=personMapper.deleteById(5L);

        System.out.println(result);// 受影响的行数
    }

结果:

数据库:

数据库中并没有删除,而是将deleted从0变为1,实现了逻辑删除。(其实就是更新操作)

MyBatis-Plus——详解常用注解_第12张图片


小结

以上就是【一心同学】整理的【MyBatis-Plus】的常用【注解】讲解,通过介绍和代码实现,相信大家基本已经掌握了,这一块的内容在我们平时的开发当中还是比较重要的,因为我们在开发当中用得最多的就是注解了,并且其能够大大提高我们的【工作效率】。

如果这篇【文章】有帮助到你,希望可以给【一心同学】点个,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点,如果有对【后端技术】感兴趣的小可爱,也欢迎关注❤️❤️❤️ 【一心同学】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】

你可能感兴趣的:(MyBatis-Plus,mybatis,plus,注解,乐观锁,逻辑删除,自动填充)