配置了公共字段自动填充类,何时会自动填充?何时不会?

22 阅读2分钟

自动填充公共字段类的实现如下:

/**
 * @author Zoe
 * @description 自定义元数据处理器,用于实现公共字段自动填充
 * @description 实现步骤:
 * @description 1.在实体类属于公共字段的属性上加上@TableField,指定自动填充策略
 * @description 2.按照框架要求编写元数据处理器,该类需要实现MetaObjectHandler接口,在此类中统一为公共字段赋值
 * @date 2025/1/12
 */
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自动填充[insert]……");
        log.info(metaObject.toString());
        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("createUser", BaseContext.getCurrentId());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自动填充[update]……");
        log.info(metaObject.toString());
        // log.info("当前线程id:(MyMetaObjectHandler){}",Thread.currentThread().getId());

        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());
    }
}

这是一个controller:

/**
 * 设置默认地址
 */
@PutMapping("default")
public R<AddressBook> setDefault(@RequestBody AddressBook addressBook) {
    log.info("addressBook:{}", addressBook);
    LambdaUpdateWrapper<AddressBook> wrapper = new LambdaUpdateWrapper<>();
    wrapper.eq(AddressBook::getUserId, BaseContext.getCurrentId());
    wrapper.set(AddressBook::getIsDefault, 0);
    // SQL:update address_book set is_default = 0 where user_id = ?
    // 此处不会自动更新公共字段
    addressBookService.update(wrapper);

    addressBook.setIsDefault(1);
    // SQL:UPDATE address_book SET is_default=?, update_time=?, update_user=? WHERE id=?
    // 此处会连公共字段一起更新
    addressBookService.updateById(addressBook);
    return R.success(addressBook);
}

在代码中,两次更新操作对公共字段的自动填充表现不同,核心原因在于MyBatis-Plus的自动填充机制只对实体对象的字段生效,而对条件构造器(Wrapper)的更新不生效。具体分析如下:

1. addressBookService.update(wrapper); 不自动填充公共字段

  • 该操作通过 LambdaUpdateWrapper 直接构造更新条件和字段(set(AddressBook::getIsDefault, 0)),本质是生成一条 UPDATE address_book SET is_default = 0 WHERE user_id = ? 的SQL
  • 这种方式没有通过实体对象(AddressBook)设置字段,而是直接通过条件构造器指定更新内容,因此不会触发MyMetaObjectHandler的自动填充逻辑(自动填充依赖实体对象的字段赋值)。所以公共字段(如updateTime、updateUser)不会被自动更新。

2. addressBookService.updateById(addressBook); 会自动填充公共字段

  • 该操作通过实体对象 addressBook 进行更新,updateById 方法会将实体对象中的非空字段纳入更新范围。
  • 由于实体类中,公共字段必然添加了 @TableField(fill = FieldFill.UPDATE) 注解(这是自动填充的前提),因此MyBatis-Plus 会在执行更新前调用MyMetaObjectHandler的updateFill方法,自动为这些字段赋值。
  • 最终生成SQL: UPDATE address_book SET is_default=?, update_time=?, update_user=? WHERE id=?