MyBatis Plus实现时间字段自动填充的完整方案

2025-09-14 11:50

本文主要是介绍MyBatis Plus实现时间字段自动填充的完整方案,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,...

前言

在日常开发中,我们经常需要记录数据的创建时间和更新时间。传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏。本文将介绍如何使用 MyBATis Plus 的自动填充功能来优雅地解决这个问题。

解决目标

  • 创建记录时自动设置 createTimeupdateTime
  • 更新记录时自动更新 updateTime,保持 createTime 不变
  • 无需手动编写时间设置代码
  • 统一的时间管理机制

技术栈

  • 框架: Spring Boot + MyBatis Plus
  • 数据库: mysql
  • 实体管理: JPA 注解 + MyBatis Plus 注解

实现步骤

1. 实体类注解配置

首先在实体类的时间字段上添加 MyBatis Plus 的自动填充注解:

/**
 * 邮箱服务器实体类
 */
@Entity
@Table(name = "tbl_email_server")
public class EmailServer extends BaseEntity {
    
    // 其他字段...
    
    /** 创建时间 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;

    /** 更新时间 */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT_UPDATE)  
    private Date updateTime;
    
    // getter 和 setter 方法...
}

注解说明:

  • @TableField(fill = FieldFill.INSERT): 仅在插入操作时自动填充
  • @TableField(fill = FieldFill.INSERT_UPDATE): 在插入和更新操作时都自动填充
  • @JsonFormat: 指定 JSON 序列化时的日期格式

2. 创建元数据处理器

创建自定义的元数据处理器来实现具体的填充逻辑:

package com.ruoyi.framework.config;

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

import Java.util.Date;

/**
 * MyBatis Plus 字段自动填充处理器
 * 
 * @author ruoyi
 */
@Component
public class MyBatisMetaObjectHandler implements MetaObjectHandler {

    /**
     * 插入时的填充策略
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        Date now = new Date();
        
        // 插入时同时填充创建时间和更新时间
        this.strictInsertFill(metaObject, "createTime", Date.class, now);
        this.strictInsertFill(metaObject, "updateTime", Date.class, now);
    }

    /**
     * 更新时的填充策略  
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        // 更新时仅填充更新时间
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
    }
}

核心方法说明:

  • insertFill(): 处理插入操作的字段填充
  • updateFill(): 处理更新操作的字段填充
  • strictInsertFill(): 严格插入填充,只有当字段值为 null 时才填充
  • strictUpdateFill(): 严格更新填充,只有当字段值为 null 时才填充

3. 服务层代码优化

移除原本手动设置时间的代码:

修改前:

@Override
public int insertEmailServer(EmailServer emailServer) {
    // 手动设置时间字段
    emailServer.setCreateBy(SecurityUtils.getUsername());
    emailServer.setCreateTime(new Date());  // ❌ 需要移除
    emailServer.setUpdateTime(new Date());  // ❌ 需要移除
    return emailServerMapper.insertEmailServer(emailServer);
}

@Override
public int updateEmailServer(EmailServer emailServer) {
    emailServer.setUpdateBy(SecurityUtils.getUsername());
    emailServer.setUpdateTime(new Date());  // ❌ 需要移除  
    return emailServerMapper.updateEmailSChina编程erver(emailServer);
}

修改后:

@Override
public int insertEmailServer(EmailServer emailServer) {
    // 只设置创建者,时间字段由 MyBatis Plus 自动填充
    emailServer.setCreateBy(SecurityUtils.getUsername());
    return emailServerMapper.insertEmailServer(emailServer);
}

@Override
public int updateEmailServer(EmailServer emailServer) {
    // 只设置更新者,更新时间由 MyBatis Plus 自动填充
    emailServer.setUpdateBy(SecurityUtils.getUsername());
    return emailServerMapper.updateEmailServer(emailServer);
}

填充机制详解

创建记录时的填充过程

// 执行插入操作
EmailServer emailServer = new EmailServer();
emailServer.setServerName("SMTP服务器");
/js/ ... 设置其他业务字段

// 调用 insertEmailServer 时,MyBatis Plus 会:
// 1. 触发 insertFill 方法
// 2. createTime = 2024-01-15 10:30:25  
// 3. updateTime = 2024-01-15 10:30:25 (与创建时间相同)

更新记录时的填充过程

// 执行更新操作
EmailServer emailServer = new EmailServer();
emailServer.setServerId(1L);
emailServer.setServerName("新的服务器名称");
// ... 修改其他业务字段

// 调用 updateEmailServer 时,MyBatis Plus 会:
// 1. 触发 updateFill 方法
// 2. createTime = 保持原值不变
// 3. updateTime = 2024-01-15 14:25:30 (更新为当前时间)

数据库建议配置

虽然使用了注解自动填充,但建议在数据库层面也设置默认值作为双重保障:

-- 为时间字段添加默认值
ALTER TABLE tbl_email_server 
MODIFY COLUMN create_time datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间';

ALTER TABLE tbl_email_server 
MODIFY COLUMN update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间';

前后对比

对比项手动设置方式自动填充方式
代码量每个方法都需要设置一次配置,全局生效
维护性容易遗漏,难以统一统一管理,不易出错
一致性依赖开发者自觉性自动保证一致性
性能无额外性能消耗微小的反射开销

进阶扩展

1. 支持更多字段类型

@Override
public void insertFill(MetaObject metaObject) {
    Date now = new Date();
    
    // 支持 Date 类型
    this.strictInsertFill(metaObject, "createTime", Date.class, now);
    this.strictInsertFill(metaObject, "updateTime", Date.class, now);
    
    // 支持 LocalDateTime 类型
    this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
    this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
    
    // 支持时间戳
    this.strictInsertFill(metaObject, "createTime", Long.class, System.currentTimeMillis());
}

2. 添加创建者和更新者自动填充

@Override
public void insertFill(MetaObject metaObject) {
    Date now = new Date();
    String currentUser = getCurrentUser(); // 获取当前用户
    
    // 时间字段填充
    this.strictInsertFill(metaObject, "createTime", Date.class, now);
    this.strictInsertFill(metaObject, "updateTime", Date.class, now);
    
    // 用户字段填充
    this.strictInsertFill(metaObject, "createBy", String.class, currentUser);
    this.strijsctInsertFill(metaObject, "updateBy", String.class, currentUser);
}

@OverrXcgvqtcehide  
public void updateFill(MetaObject metaObject) {
    String currentUser = getCurrentUser();
    
    this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
    this.strictUpdateFill(metaObject, "updateBy", String.class, currentUser);
}

private String getCurrentUser() {
    try {
        return SecurityUtils.getUsername();
    } catch (Exception e) {
        return "system"; // 默认用户
    }
}

常见问题与解决方案

1. 字段没有自动填充

可能原因:

  • 实体类字段名与数据库列名不匹配
  • 忘记添加 @TableField 注解
  • MetaObjectHandler 没有被 Spring 管理

解决方案:

// 确保字段名正确映射
@TableField(value = "create_time", fill = FieldFill.INSERT)
private Date createTime;

// 确保处理器被 Spring 管理
@Component  // 必须添加此注解
public class MyBatisMetaObjectHandler implements MetaObjectHandler {
    // ...
}

2. 更新操作时创建时间被意外修改

解决方案:

// 使用 FieldFill.INSERT 而不是 INSERT_UPDATE
@TableField(fill = FieldFill.INSERT)  // ✅ 正确
private Date createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)  // ✅ 正确
private Date updateTime;

3. JSON 序列化时间格式问题

解决方案:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;

总结

MyBatis Plus 的自动填充功能为我们提供了一个优雅的解决方案来管理时间字段:

优势

  1. 自动化: 无需手动编写重复的时间设置代码
  2. 统一性: 全局统一的时间填充策略
  3. 可靠性: 避免了人为遗漏设置时间的问题
  4. 扩展性: 可以轻松扩展到其他字段的自动填充

核心实现

  1. 在实体类时间字段添加 @TableField 注解
  2. 创建实现 MetaObjectHandler 接口的处理器
  3. 在处理器中实现 insertFillupdateFill 方法
  4. 移除服务层中的手动时间设置代码

这种方案不仅提升了开发效率,还增强了代码的可维护性和一致性。在实际项目中,建议结合数据库默认值设置,形成双重保障机制。

以上就是MyBatis Plus实现时间字段自动填充的完整方案的详细内容,更多关于MyBatis Plus时间字段自动填充的资料请关注China编程(www.chinasem.cn)其它相关文章!

这篇关于MyBatis Plus实现时间字段自动填充的完整方案的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1155913

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

MyBatis常用XML语法详解

《MyBatis常用XML语法详解》文章介绍了MyBatis常用XML语法,包括结果映射、查询语句、插入语句、更新语句、删除语句、动态SQL标签以及ehcache.xml文件的使用,感兴趣的朋友跟随小... 目录1、定义结果映射2、查询语句3、插入语句4、更新语句5、删除语句6、动态 SQL 标签7、ehc

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

Nginx搭建前端本地预览环境的完整步骤教学

《Nginx搭建前端本地预览环境的完整步骤教学》这篇文章主要为大家详细介绍了Nginx搭建前端本地预览环境的完整步骤教学,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录项目目录结构核心配置文件:nginx.conf脚本化操作:nginx.shnpm 脚本集成总结:对前端的意义很多

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

MyBatis延迟加载与多级缓存全解析

《MyBatis延迟加载与多级缓存全解析》文章介绍MyBatis的延迟加载与多级缓存机制,延迟加载按需加载关联数据提升性能,一级缓存会话级默认开启,二级缓存工厂级支持跨会话共享,增删改操作会清空对应缓... 目录MyBATis延迟加载策略一对多示例一对多示例MyBatis框架的缓存一级缓存二级缓存MyBat

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、