莫张周刘王 发表于 2025-4-17 20:43:13

MyBatis与MyBatis-Plus:字段主动填充的两种实现方式

目次
1. 使用 MyBatis 拦截器实现字段主动填充
2. 使用 MyBatis-Plus 实现字段主动填充

1. 使用 MyBatis 拦截器实现字段主动填充

实现步调


[*] 创建拦截器 实现 MyBatis 的 Interceptor 接口,通过拦截 MyBatis 实行的 SQL 操作来主动填充公共字段
@Intercepts({
    @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class CommonFieldInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
      if (invocation.getArgs().length > 1) {
            Object parameter = invocation.getArgs();
            if (parameter instanceof BaseEntity) {
                BaseEntity entity = (BaseEntity) parameter;
                if (isInsertOperation(invocation)) {
                  entity.setCreateTime(new Date());
                  entity.setUpdateTime(new Date());
                } else if (isUpdateOperation(invocation)) {
                  entity.setUpdateTime(new Date());
                }
            }
      }
      return invocation.proceed();
    }

    private boolean isInsertOperation(Invocation invocation) {
      String methodName = ((MappedStatement) invocation.getArgs()).getId();
      return methodName.contains("insert");
    }

    private boolean isUpdateOperation(Invocation invocation) {
      String methodName = ((MappedStatement) invocation.getArgs()).getId();
      return methodName.contains("update");
    }

    @Override
    public Object plugin(Object target) {
      return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
      // 可选:设置属性
    }
}
[*] 定义基础实体类 创建一个基础实体类 BaseEntity,包含需要主动填充的公共字段,全部需要主动填充的实体类都应继承该类
public class BaseEntity {
    private Date createTime;
    private Date updateTime;

    // getters and setters
    public Date getCreateTime() {
      return createTime;
    }

    public void setCreateTime(Date createTime) {
      this.createTime = createTime;
    }

    public Date getUpdateTime() {
      return updateTime;
    }

    public void setUpdateTime(Date updateTime) {
      this.updateTime = updateTime;
    }
}
[*] 配置拦截器 在 MyBatis 配置文件中注册拦截器
<plugins>
    <plugin interceptor="com.example.mybatis.interceptor.CommonFieldInterceptor"/>
</plugins>
[*] 使用示例 创建一个继承 BaseEntity 的实体类,并在 Mapper 中使用该实体类举行数据库操作
public class User extends BaseEntity {
    private Long id;
    private String name;

    // getters and setters
    public Long getId() {
      return id;
    }

    public void setId(Long id) {
      this.id = id;
    }

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }
} @Mapper
public interface UserMapper {
    @Insert("INSERT INTO user (name, create_time, update_time) VALUES (#{name}, #{createTime}, #{updateTime})")
    void insert(User user);

    @Update("UPDATE user SET name = #{name}, update_time = #{updateTime} WHERE id = #{id}")
    void update(User user);
}
2. 使用 MyBatis-Plus 实现字段主动填充

实现步调


[*] 定义实体类 在实体类中,使用 @TableField 注解来标记需要主动填充的字段,并指定填充策略
@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)
    private Integer id;

    private String username;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createdAt;// 创建时自动填充

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updatedAt;// 创建和更新时自动填充
}
[*] 实现 MetaObjectHandler 创建一个类实现 MetaObjectHandler 接口,并重写 insertFill 和 updateFill 方法,定义插入和更新时的填充逻辑。
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
      this.strictInsertFill(metaObject, "createdAt", LocalDateTime::now, LocalDateTime.class);
      this.strictInsertFill(metaObject, "updatedAt", LocalDateTime::now, LocalDateTime.class);
    }

    @Override
    public void updateFill(MetaObject metaObject) {
      this.strictUpdateFill(metaObject, "updatedAt", LocalDateTime::now, LocalDateTime.class);
    }
}
[*] 配置主动填充处理器 确保 MyMetaObjectHandler 类被 Spring 管理,可以通过 @Component 或 @Bean 注解来实现。
[*] 使用示例 创建一个继承自 BaseMapper 的 Mapper 接口
@Mapper
public interface UserMapper extends BaseMapper<User> {
} 测试代码
@Component
public class MyTestRunner implements CommandLineRunner {
    @Autowired
    private UserMapper userMapper;

    @Override
    public void run(String... args) throws Exception {
      // 测试插入时自动填充
      User user = new User();
      user.setUsername("John Doe");
      userMapper.insert(user);
      System.out.println("Inserted user: " + user);

      // 测试更新时自动填充
      user.setUsername("Jane Doe");
      userMapper.updateById(user);
      System.out.println("Updated user: " + user);
    }
}
两种方式的对比



[*] MyBatis 拦截器方式

[*] 优点:灵活性高,可以自定义复杂的填充逻辑,适用于复杂的业务场景。
[*] 缺点:实现相对复杂,需要编写较多代码,且需要手动添加注解。

[*] MyBatis-Plus 方式

[*] 优点:使用简单,代码量少,开箱即用,与 MyBatis-Plus 无缝集成。
[*] 缺点:填充逻辑相对固定,扩展性较差。

选择建议



[*] 假如需要实现简单的主动填充功能,如创建时间和更新时间的主动填充,推荐使用 MyBatis-Plus 方式。
[*] 假如有复杂的业务逻辑,需要自定义填充逻辑,推荐使用 MyBatis 拦截器方式。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: MyBatis与MyBatis-Plus:字段主动填充的两种实现方式