Appearance
MyBatis-Plus 自动填充
自动填充是指在插入或更新数据时,自动为某些字段赋值(如 create_time、update_time、create_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 方法触发 |
