myBatis-plus自动填充插件

news2024/11/27 6:14:39

在 MyBatis-Plus 3.x 中,自动填充的插件方式发生了变化。现在推荐使用 MetaObjectHandler 接口的实现类来定义字段的填充逻辑。以下是使用 MyBatis-Plus 3.x 自动填充的基本步骤:

1.基本配置

1.1添加 Maven 依赖:

确保你的 Maven 依赖中使用的是 MyBatis-Plus 3.x 版本。

<dependencies>
    <!-- MyBatis-Plus 核心依赖 -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>最新版本</version>
    </dependency>
    
    <!-- 其他依赖... -->
</dependencies>

1.2 配置 MyBatis-Plus 自动填充

1.2.1使用@Component注解

创建一个实现 MetaObjectHandler 接口的配置类,用于定义字段填充逻辑。

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

这种方式是 MyBatis-Plus 3.x 中推荐的字段自动填充方式。在这个示例中,MyMetaObjectHandler 类上添加了 @Component 注解,确保 Spring Boot 能够自动扫描到并注册为 Bean。这样,MyBatis-Plus 在执行插入和更新操作时会自动调用 MetaObjectHandler 中的对应方法进行字段填充

1.2.1 使用@Bean+@Configuration注解

当然也可以使用@bean的方式在mybatisConfig里面注入


import com.sky.handler.MyMetaObjectHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisPlusConfig {

    @Bean
    public MyMetaObjectHandler myMetaObjectHandler() {
        return new MyMetaObjectHandler();
    }
}
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;

@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {


    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("开始插入时自动填充");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("开始更新时自动填充");
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    }
}

但是用这种方式的时候需要注意MyMetaObjectHandler这个类前面不能加Component,否则会造成bean冲突。

定义实体类:
在实体类中定义需要自动填充的字段:

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

import java.time.LocalDateTime;

@Data
@TableName("your_table_name")
public class YourEntity {

    @TableId
    private Long id;

    private String name;

    // 其他字段省略...
    
    // createTime 和 updateTime 字段将由 MyBatis-Plus 自动填充
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

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

确保你的实体类中的字段类型和配置的 MetaObjectHandler 中的类型一致。

这样达到的实际效果就是

我们在封装好入库的对象的时候,没有setUpdateTime这个属性,那么执行intsert 和 update操作的之后,数据库中也会向UpdateTime存入值。

下面我们需要对一些细节说明一下

2. 严格模式与非严格模式

this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());

在这个示例中,MyMetaObjectHandler 实现了 MetaObjectHandler 接口,并在 insertFill 和 updateFill 方法中定义了字段填充的逻辑。strictInsertFill 和 strictUpdateFill 方法用于严格模式的字段填充。

非严格模式: 在非严格模式下,字段填充通常会在任何情况下都执行,即使字段的值已经被手动设置或者数据库中已经有了一个值。这样可能导致字段值被多次更新,。

严格模式: 相比之下,严格模式会更加谨慎。在严格模式下,字段填充只会在满足一定条件的情况下才执行。例如,在插入操作时,只有在字段的值为 null 时才会进行填充。在更新操作时,只有在字段的值为 null 或者被标记为需要更新时才会进行填充。

3.自动插入的时机

上述的自动填充操作是发生在数据库层面的

具体说是在 MyBatis 执行 SQL 语句时,MyBatis-Plus 框架会拦截这些 SQL 操作,根据配置的自动填充规则来动态生成相应的字段值,然后执行相应的 SQL 操作。这样可以在数据库层面确保这些字段的值符合预期。

插入操作: 当执行插入 SQL 语句时,MyBatis-Plus 拦截器会在插入前执行 MetaObjectHandler 的 insertFill 方法,填充相应字段的值,然后将填充后的 SQL 语句发送给数据库执行。

更新操作: 同理,对于更新 SQL 语句,MyBatis-Plus 会在更新前执行 MetaObjectHandler 的 updateFill 方法,填充相应字段的值,然后将填充后的 SQL 语句发送给数据库执行。

这样做的好处是在数据库层面确保了字段填充的一致性,避免了手动在 Service 层面或者 Controller 层面进行填充,减少了代码冗余和错误的可能性。这也是 MyBatis-Plus 提供的一种便捷的开发方式,使得开发者可以更专注于业务逻辑而不用过多关心数据库层面的操作。

注意:上述操作并不是废话,我们来看这样一个例子(这个例子是我实际项目中的例子,我们只需要关注自动填充相关的部分就可以)

实体类

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("employee")
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;

    @TableId(type = IdType.AUTO)//自增主键
    private Long id;

    @TableField(insertStrategy = FieldStrategy.NOT_EMPTY)
    private String username;

    @TableField(insertStrategy = FieldStrategy.NOT_EMPTY)
    private String name;

    @TableField(insertStrategy = FieldStrategy.NOT_EMPTY)
    private String password;

    @TableField(insertStrategy = FieldStrategy.NOT_EMPTY)
    private String phone;

    @TableField(insertStrategy = FieldStrategy.NOT_EMPTY)
    @EnumValue()
    private String sex;

    @TableField(value = "id_number",insertStrategy = FieldStrategy.NOT_NULL)
    private String idNumber;

    private EmployeeStatus status;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT)//表示该字段只会在插入的填充
    private LocalDateTime createTime;


    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT_UPDATE)//表示这个字段只会在传入和更改的时候都会填充
    private LocalDateTime updateTime;

    @TableField(fill = FieldFill.INSERT)//表示该字段只会在插入的填充
    private Long createUser;

    @TableField(fill = FieldFill.INSERT_UPDATE)//表示该字段只会在插入的填充
    private Long updateUser;
}

}

我的自动填充是这样写的

@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {


    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("开始插入时自动填充");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class,LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("开始更新时自动填充");
        this.strictUpdateFill(metaObject, "updateTime",LocalDateTime.class, LocalDateTime.of(2022,12,30,5,6,0));
    }
}

我这里写了一个测试类

@SpringBootTest
class SkyApplicationTest {
    @Resource
    EmployeeMapper employeeMapper;
    @Test
    public  void test() {
        LambdaUpdateWrapper<Employee> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Employee::getName,"张三");
        lambdaUpdateWrapper.set(Employee::getPhone,"2222222222");

        Employee employee  = new Employee();
        employee.setPhone("111111111");

        employeeMapper.update(employee,lambdaUpdateWrapper);
        System.out.println("");
    }

}

那么这个sql执行的结果是什么?

UPDATE
        employee 
    SET
        phone='111111111',
        update_time='2022-12-30T05:06',
        update_user=null,
        phone='2222222222' 
    WHERE
        (
            name = '张三'
        );

这个sql为什么是这样的

我们先看phone这个字段
phone这个字段是没有设置自动填充的,但是两个入参,实体类Employee,和更新条件LambdaUpdateWrapper都对phone都对phone设置了值。
通过sql我们不难发现,mybatis-plus会先根据实体类中不为null的值进行set,然后再写入更新条件中的set
所以,最后更新到数据库里,谁写在SQL语句的最后,数据库里的值就会是谁。

下面

        update_time='2022-12-30T05:06',
        update_user=null,

这两个字段都是自动填充设置的,其中update_time=‘2022-12-30T05:06’,是我设置了固定值,而update_user=null,是因为我没在MyMetaObjectHandler里设置值的原因,才会赋值为null.

那么现在的问题是自动插入的时机在哪呢?

我们不妨构建这样的例子

 @Override
    public void insertFill(MetaObject metaObject) {
        log.info("开始插入时自动填充");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class,LocalDateTime.now());
        this.strictInsertFill(metaObject,"updateUser",Long.class,1L);
        this.strictInsertFill(metaObject,"createUser",Long.class,1L);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("开始更新时自动填充");
        this.strictUpdateFill(metaObject, "updateTime",LocalDateTime.class, LocalDateTime.of(2022,12,30,5,6,0));
        this.strictInsertFill(metaObject,"updateUser",Long.class,1L);
    }

自动填充的时候,uptdateUser会被填入1L

@Test
    public  void test() {
        LambdaUpdateWrapper<Employee> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Employee::getName,"张三");
        lambdaUpdateWrapper.set(Employee::getUpdateUser,2L);

        Employee employee  = new Employee();
        employee.setUpdateUser(3L);

        employeeMapper.update(employee,lambdaUpdateWrapper);
        System.out.println("");
    }

而在测试类中。实体类Employee中的updateUser值是3L
查询条件中的updateUser是2L

那么形成的SQL是什么样的呢?

/*17 2023-12-17 16:52:32   */

    UPDATE
        employee 
    SET
        update_time='2022-12-30T05:06',
        update_user=3,
        update_user=2 
    WHERE
        (
            name = '张三'
        );

先update_user = 3,后update_user = 2,这个之前就解释过了
但是update = 1怎么没有呢?

这是因为前面说的我们在设置自动填充时遵循的时严格模式的插入,当执行update操作的时候,如果该实体类中的updat_user不为null,就不会触发字段填充。

严格模式下的填充规则
插入时填充规则(INSERT):

当执行插入操作时,只有在实体类的字段的值为 null 时才进行填充。
如果实体类字段的值不为 null,则填充操作会被忽略。
更新时填充规则(UPDATE):

当执行更新操作时,只有在字段的值为 null 或者字段被标记为需要更新时才进行填充。
如果字段的值不为 null,且字段没有被标记为需要更新,填充操作会被忽略。

一定一定注意,是实体类中的字段值为null

我们将测试类更改一下:


@SpringBootTest
class SkyApplicationTest {
    @Resource
    EmployeeMapper employeeMapper;
    @Test
    public  void test() {
        LambdaUpdateWrapper<Employee> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Employee::getName,"张三");
        lambdaUpdateWrapper.set(Employee::getUpdateUser,2L);

        Employee employee  = new Employee();
//        employee.setUpdateUser(3L);

        employeeMapper.update(employee,lambdaUpdateWrapper);
        System.out.println("");
    }

}

我们将实体类中updateUser设置为null

你会发现生成的SQL语言是

    UPDATE
        employee 
    SET
        update_time='2022-12-30T05:06',
        update_user=1,
        update_user=2 
    WHERE
        (
            name = '张三'
        );

会发现,自动填充是触发了的。
并且在lambdaUpdateWrapper这个更新条件的前面。这是因为本质上,自动填充是给实体类的update_time赋值的。

此外还有一个注意点,有一种情况也会导致自动填充失效。

在mybatispluss的官网也有说明。
https://baomidou.com/pages/4c6bcf/
在这里插入图片描述

看下面这个例子

@SpringBootTest
class SkyApplicationTest {
    @Resource
    EmployeeMapper employeeMapper;
    @Test
    public  void test() {
        LambdaUpdateWrapper<Employee> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        lambdaUpdateWrapper.eq(Employee::getName,"张三");
        lambdaUpdateWrapper.set(Employee::getUpdateUser,2L);

//        Employee employee  = new Employee();
//        employee.setUpdateUser(3L);

        employeeMapper.update(null,lambdaUpdateWrapper);
        System.out.println("");
    }

}

他的sql实际为

UPDATE
        employee 
    SET
        update_user=2 
    WHERE
        (
            name = '张三'
        );

之所以会这样,update的实体类入参是null,自动填充根本就没有启动。

所以当我们的实体类在定义的时候使用了@TableField(fill = FieldFill.*****)的时候,使用mybatis-plus自带的update方法的时候一定不能传null的实体类。可以传new my_entity()过来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1318683.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

数据结构之<图>的介绍

图&#xff08;Graph&#xff09;的概念&#xff1a; 在数据结构中&#xff0c;图是由节点&#xff08;顶点&#xff09;和边组成的非线性数据结构。图用于表示不同对象之间的关系&#xff0c;其中节点表示对象&#xff0c;边表示对象之间的连接或关系。 1.图的基本组成元素&a…

Jenkins----基于 CentOS 或 Docker 安装部署Jenkins并完成基础配置

查看原文 文章目录 基于 CentOS7 系统部署 Jenkins 环境基于 Docker 安装部署 Jenkins环境配置 Jenkins 中文模式配置用户名密码形式的 Jenkins 凭据配置 ssh 私钥形式的 Jenkins 凭据配置 Jenkins 执行任务的节点 基于 CentOS7 系统部署 Jenkins 环境 &#xff08;1&#xff…

广东高院严惩“套路贷”犯罪,保护校园安全

近日&#xff0c;广东高院发布了一批依法严惩“套路贷”犯罪的典型案例&#xff0c;其中一起涉及在校学生的“套路贷”案件引起了广泛关注。 这起案件中&#xff0c;张某等人针对在校大学生开展无抵押高息短期借款“套路贷”业务&#xff0c;通过频繁威胁恐吓、借新还旧、转单…

【计算机视觉--解耦视频分割跟踪任何物体】

UIUC&Adobe开源|无需监督&#xff0c;使用解耦视频分割跟踪任何物体&#xff01;视频分割的训练数据往往昂贵且需要大量的标注工作。这限制了将端到端算法扩展到新的视频分割任务&#xff0c;特别是在大词汇量的情况下。为了在不为每个个别任务训练视频数据的情况下实现“跟…

NtripShare Mos监测平台边缘计算终端与自动优化平差算法

忙忙乎乎23年又要过去了&#xff0c;回头看今年做的事&#xff0c;只有两件事值得一提&#xff1a; 1、自动化监测边缘计算终端&#xff1b; 2、自动优化平差算法。 自动化监测边缘计算终端 终端采用全国产硬件方案终端支持全站仪供电控制终端支持远程控制终端支持数据缓存技…

力扣刷题-二叉树-二叉树的所有路径

257 二叉树的所有路径 给定一个二叉树&#xff0c;返回所有从根节点到叶子节点的路径。 说明: 叶子节点是指没有子节点的节点。 示例: 思路 参考&#xff1a; https://www.programmercarl.com/0257.%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E6%89%80%E6%9C%89%E8%B7%AF%E5%BE…

嵌入式开发中的总线与时钟

总线 AHB总线 AHB的全称是"Advanced High-performance Bus",中文翻译就是"高级高性能总线"。这是一种在计算机系统中用于连接不同硬件组件的总线架构,它可以帮助这些组件之间高效地传输数据和信息。这个总线架构通常用于处理速度较快且对性能要求较高的…

Markdown编辑器常用颜色背景指南(附颜色与代码展示,cv即可用)

目录 一.字体颜色1)常用html代码2)通过【颜色代码表】直接改写 二.字体背景颜色1)常用html代码 一.字体颜色 1)常用html代码 html代码 <font colorred> text </font> 常用颜色及其对应的十六进制和颜色名: 红色 p 红色 #FF0000 red <font color#FF0000> t…

springboot整合vue,将vue项目整合到springboot项目中

将vue项目打包后&#xff0c;与springboot项目整合。 第一步&#xff0c;使用springboot中的thymeleaf模板引擎 导入依赖 <!-- thymeleaf 模板 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-t…

Frontier ,MDPI T3系列,植物科学领域高质量期刊分级目录发布!

公众号&#xff1a;生信漫谈&#xff0c;获取最新科研信息&#xff01; Frontier &#xff0c;MDPI T3系列&#xff0c;植物科学领域高质量期刊分级目录发布&#xff01;https://mp.weixin.qq.com/s/ukbjIgdyaza7LmKmZmy5bw 2023年3月31日&#xff0c;中国科学技术大学科研部…

运筹学经典问题(二):最短路问题

问题描述 给定一个图&#xff08;有向图或无向图&#xff09; G ( V , E ) G (V, E) G(V,E)&#xff0c; V V V是图中点的集合&#xff0c; E E E是图中边的集合&#xff0c;图中每条边 ( i , j ) ∈ E (i, j) \in E (i,j)∈E都对应一个权重 c i j c_{ij} cij​&#xff08;…

第7章 排序

前言 在这一章&#xff0c;我们讨论数组元素的排序问题。为简单起见&#xff0c;假设在我们的例子中数组只包含整数&#xff0c;虽然更复杂的结构显然也是可能的。对于本章的大部分内容&#xff0c;我们还假设整个排序工作能够在主存中完成&#xff0c;因此&#xff0c;元素的个…

Redis Cluster集群搭建 三主三从

Redis包下载 Linux&#xff1a; http://download.redis.io/releases/ Mac or Windows: https://redis.io/download/ 2.下载后解压进入文件夹&#xff08;本次我的Redis版本是6.2.14版本&#xff09; /redis/redis-6.2.14 开始安装 make instarll修改配置文件复制redis.conf 6…

pve8.1版本安装及环境初始化过程记录

背景 经历pve旧版本奔溃事件&#xff0c;果断重新购买了装备&#xff0c;做个稳定的pve环境&#xff0c;旧主机用于折腾其他系统&#xff0c;硬盘一定要用好的。 1.pve8.1.3系统版本安装 下载地址 Download Proxmox software, datasheets, agreements 使用种子下载会快一点儿…

英伟达盒子 Jetson Xshell连接串口查看日志方法(串口日志、盒子日志)

文章目录 连接串口xshell连接串口信息 连接串口 接盒子上的A2、B2&#xff0c;以及接地线&#xff1a; 另外一头接上电脑&#xff08;我用的RS485转USB工具&#xff09;&#xff1a; xshell连接 协议选择SERIAL&#xff1a; 设置盒子厂商约定的端口号、波特率、数据位、停止位…

ElaticSearch 是如何建立索引的?

前面讲到了 NoSQL 数据库的应用&#xff0c;在关系型数据库和 NoSQL 数据库之外&#xff0c;还有一类非常重要的存储中间件&#xff0c;那就是文件索引。当你在电商网站搜索商品&#xff0c;或者在搜索引擎搜索资料时&#xff0c;都离不开基于文件索引的各种检索框架的支持。 …

十二星座对音乐有感觉但是唱得最不着调的排名。

第一名&#xff08;狮子座&#xff09;、第二名&#xff08;水瓶座&#xff09;、第三名&#xff08;射手座&#xff09; 第四名&#xff08;金牛座&#xff09;、第五名&#xff08;摩羯座&#xff09;、第六名&#xff08;天秤座&#xff09; 第七名&#xff08;巨蟹座&#…

03 使用Vite开发Vue3项目

概述 要使用vite创建Vue3项目&#xff0c;有很多种方式&#xff0c;如果使用命令&#xff0c;则推荐如下命令&#xff1a; # 使用nvm将nodejs的版本切换到20 nvm use 20# 全局安装yarn npm install -g yarn# 使用yarnvite创建项目 yarn create vite不过&#xff0c;笔者更推荐…

解决“bat中文路径乱码“问题

今天&#xff0c;在使用.bat脚本&#xff0c;将hello.png从"D:\mypic\备份"目录&#xff0c;拷贝到"D:\mypic\备份"时&#xff1b;发现中文乱码,弹出如下对话框: 图(1) bat中文路径乱码 原来的命令是&#xff1a; copy D:\mypic\one\hello.png D:\mypic\备…

WordPress VIP收费下载插件Erphpdown v17.0.1 开心版

会员推广下载专业版 WordPress插件&#xff08;erphpdown&#xff09;是模板兔开发的一款针对虚拟资源收费下载/付费下载/付费视频/收费查看/付费阅读/付费查看/VIP下载查看的插件&#xff0c;经过完美测试运行于wordpress 3.x-5.x版本。后续模板兔会增加更多实用的功能。 模板…