MyBatis-Plus 提供的不同填充策略,各有特点和适用场景:
方法对比表
| 特性 | strictInsertFill/strictUpdateFill | fillStrategy | setFieldValByName |
|---|---|---|---|
| 版本 | 3.3.0+ | 3.0+ | 3.0+ |
| 严格模式 | ✅ 严格类型检查 | ❌ 不检查类型 | ❌ 不检查类型 |
| 空值覆盖 | ❌ 已有值不覆盖 | ✅ 空值才填充 | ✅ 总是覆盖 |
| 推荐指数 | ⭐⭐⭐⭐⭐ (推荐) | ⭐⭐⭐⭐ | ⭐⭐ |
详细对比
1.strictInsertFill/strictUpdateFill(推荐使用)
特点:
严格类型检查,避免类型错误
如果字段已有值,不会覆盖(安全)
需要明确指定字段类型
java
@Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { // 严格模式 - 推荐使用 this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "createBy", String.class, getCurrentUser()); // 如果实体类中已经设置了 createTime,这里不会覆盖 } @Override public void updateFill(MetaObject metaObject) { this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); this.strictUpdateFill(metaObject, "updateBy", String.class, getCurrentUser()); } }场景:适合大多数情况,特别是需要类型安全和避免意外覆盖的场景。
2.fillStrategy
特点:
宽松模式,不检查类型
只有字段值为 null 时才填充
更灵活但不够安全
java
@Override public void insertFill(MetaObject metaObject) { // 策略模式 - 字段为null时才填充 this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 相当于: // if (metaObject.getValue("createTime") == null) { // metaObject.setValue("createTime", LocalDateTime.now()); // } }场景:当你确定不会出现类型错误,且希望空值才填充时使用。
3.setFieldValByName(不推荐)
特点:
最原始的方法
强制设置,总是覆盖已有值
没有类型检查,容易出错
java
@Override public void insertFill(MetaObject metaObject) { // 强制设置 - 总是覆盖 this.setFieldValByName("createTime", LocalDateTime.now(), metaObject); this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject); // 即使实体类已经设置了 createTime,也会被覆盖! }场景:基本不需要使用,除非你有特殊需求需要强制覆盖。
实际示例对比
场景:实体类已经设置了值
java
User user = new User(); user.setCreateTime(LocalDateTime.of(2023, 1, 1, 0, 0)); // 手动设置 user.setName("test"); userMapper.insert(user);不同方法的结果:
java
// 1. strictInsertFill - 保护已有值 this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 结果:createTime = 2023-01-01T00:00 (不覆盖) // 2. fillStrategy - 空值才填充 this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 结果:createTime = 2023-01-01T00:00 (不覆盖,因为不是null) // 3. setFieldValByName - 强制覆盖 this.setFieldValByName("createTime", LocalDateTime.now(), metaObject); // 结果:createTime = 当前时间 (强制覆盖)类型安全对比
java
// 1. strictInsertFill - 编译时检查 this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // ✅ 正确:类型匹配 this.strictInsertFill(metaObject, "createTime", Date.class, new Date()); // ❌ 错误:类型不匹配,但编译可能通过,运行时报错或填充失败 // 2. fillStrategy - 运行时才可能发现错误 this.fillStrategy(metaObject, "createTime", new Date()); // ❌ 危险:类型不匹配,可能运行时出错或数据错误 // 3. setFieldValByName - 同样危险 this.setFieldValByName("createTime", new Date(), metaObject); // ❌ 危险:类型不匹配性能对比
实际上性能差异很小,但:
strictInsertFill有额外的类型检查,略微增加开销fillStrategy和setFieldValByName更直接
但这点性能差异可以忽略不计。
最佳实践建议
推荐方案
java
@Component @Slf4j public class AutoFillHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { // 使用严格模式 - 安全第一 this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "createBy", String.class, getCurrentUser()); this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); this.strictInsertFill(metaObject, "updateBy", String.class, getCurrentUser()); } @Override public void updateFill(MetaObject metaObject) { // 使用严格模式 this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); this.strictUpdateFill(metaObject, "updateBy", String.class, getCurrentUser()); } }特殊情况处理
java
@Override public void insertFill(MetaObject metaObject) { // 混合使用:严格模式 + 策略模式 // 1. 时间字段用严格模式(避免类型错误) this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 2. 业务字段用策略模式(更灵活) this.fillStrategy(metaObject, "department", getDefaultDepartment()); // 3. 确定需要覆盖的用setField(极少情况) // this.setFieldValByName("systemFlag", "Y", metaObject); }debug 日志
java
@Override public void insertFill(MetaObject metaObject) { log.debug("开始自动填充插入字段"); try { this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); log.debug("填充 createTime 成功"); } catch (Exception e) { log.warn("填充 createTime 失败,使用策略模式", e); this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); } }总结
| 选择 | 说明 |
|---|---|
| 90% 场景 | 使用strictInsertFill/strictUpdateFill |
| 灵活场景 | 使用fillStrategy |
| 几乎不用 | setFieldValByName |
简单记忆:
要安全→
strictInsertFill要灵活→
fillStrategy要强制→
setFieldValByName
在 Spring Boot + MyBatis-Plus 项目中,推荐始终使用strictInsertFill和strictUpdateFill,这是最安全、最现代的做法。