Skip to content

MyBatis-Plus 自动填充

  自动填充是指在插入或更新数据时,自动为某些字段赋值(如 create_timeupdate_timecreate_by 等),避免每次手动设置。

一、为什么需要自动填充?

java
// 没有自动填充:每次都要手动设置
User user = new User();
user.setName("张三");
user.setCreateTime(new Date());  // 手写
user.setUpdateTime(new Date());   // 手写
userMapper.insert(user);

// 有自动填充:不用关心这些字段
User user = new User();
user.setName("张三");
userMapper.insert(user);  // createTime、updateTime 自动填充

二、配置方式

2.1 实体类标注

java
@Data
public class User {

    private Long id;
    private String name;

    @TableField(fill = FieldFill.INSERT)
    private Date createTime;  // 插入时自动填充

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;  // 插入和更新时自动填充

    @TableField(fill = FieldFill.INSERT)
    private String createBy;  // 创建人

    @TableField(fill = FieldFill.UPDATE)
    private String updateBy;  // 修改人
}

FieldFill 枚举:

触发时机
DEFAULT默认不处理
INSERT插入时填充
UPDATE更新时填充
INSERT_UPDATE插入和更新时填充

2.2 自定义填充处理器

java
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        // 插入时自动填充
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
        this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
        this.strictInsertFill(metaObject, "createBy", String.class, getCurrentUser());
        this.strictInsertFill(metaObject, "deleted", Integer.class, 0);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 更新时自动填充
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
        this.strictUpdateFill(metaObject, "updateBy", String.class, getCurrentUser());
    }

    /**
     * 获取当前登录用户
     */
    private String getCurrentUser() {
        // 从上下文获取当前用户
        return "admin";
    }
}

2.3 更灵活的填充方式

java
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        // 方式一:strictInsertFill(字段为 null 才填充)
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());

        // 方式二:setFieldValByName(无论是否为 null 都填充)
        this.setFieldValByName("updateTime", new Date(), metaObject);

        // 方式三:fillStrategy(自定义填充策略)
        this.fillStrategy(metaObject, "createBy", getCurrentUser());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        // 严格填充:字段为 null 才填充
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());

        // 强制填充:忽略 null 检查
        this.setFieldValByName("updateBy", getCurrentUser(), metaObject);
    }
}

三、使用 LocalDateTime

java
@Data
public class User {

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

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

@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());
    }
}

四、通用填充处理器

java
@Component
public class BaseMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        // 通用:自动填充所有实体共有的字段
        fillIfNull(metaObject, "createTime", LocalDateTime.now());
        fillIfNull(metaObject, "updateTime", LocalDateTime.now());
        fillIfNull(metaObject, "deleted", 0);
        fillIfNull(metaObject, "version", 1);
    }

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

    /**
     * 字段为 null 时才填充
     */
    private void fillIfNull(MetaObject metaObject, String fieldName, Object value) {
        if (metaObject.hasGetter(fieldName)) {
            Object currentValue = metaObject.getValue(fieldName);
            if (currentValue == null) {
                this.setFieldValByName(fieldName, value, metaObject);
            }
        }
    }
}

五、自动填充原理

自动填充执行流程:

  ① 解析实体类 @TableField(fill = ...) 注解
     → 记录哪些字段需要自动填充

  ② 执行 INSERT/UPDATE 时
     → ParameterHandler 设置参数前

  ③ 调用 MetaObjectHandler.insertFill() 或 updateFill()
     → 为标记了 fill 的字段赋值

  ④ 继续执行正常的参数绑定和 SQL 执行

六、注意事项

① 字段已经有值不会覆盖
   strictInsertFill 只在字段为 null 时填充
   如果手动设置了 createTime,不会覆盖

② 批量操作也会自动填充
   insertBatch、updateBatchById 等都会触发

③ 自定义 SQL 不会自动填充
   手写 XML 或注解的 SQL 不会触发自动填充
   需要手动设置字段值

④ @TableField 必须标注
   只有加了 fill 属性的字段才会被自动填充

七、速记总结

自动填充三步走:
  ① 实体类加注解:@TableField(fill = FieldFill.INSERT)
  ② 实现 MetaObjectHandler:insertFill() / updateFill()
  ③ 注册为 @Component

填充时机:
  INSERT → insertFill()
  UPDATE → updateFill()
  INSERT_UPDATE → 两个都触发

速记口诀:
  注解标注填啥时,Handler 实现填啥值,
  插入更新自动设,时间用户不用写。

八、面试要点

问题答案要点
自动填充怎么实现?@TableField(fill) + MetaObjectHandler
strictInsertFill 和 setFieldValByName 区别?strict 只填充 null,set 强制填充
自定义 SQL 会触发吗?不会,只有 BaseMapper 方法触发