c语言编程笔录

首页 >   > 笔记大全

笔记大全

MyBatisPlus自动化填充的坑怎么解决

更新时间:2023-12-14

前言:

MyBatisPlus是一个优秀的ORM框架,它在MyBatis的基础上进行了扩展,提供了更加便捷的操作数据库的方式。其中自动填充功能是MyBatisPlus的一个重要特性,它可以在插入和更新记录时自动填充一些公共字段(如创建时间、更新时间等)。然而,在使用自动填充功能时,我们可能会遇到一些坑。接下来,我将介绍一些常见的问题和解决方案。

问题1:自动填充字段的值为空

当我们在实体类中定义了需要自动填充的字段,并配置了自动填充策略后,期望这些字段在插入和更新操作时会自动填充相应的值。然而,有时候我们会发现这些自动填充的字段的值为空,这是为什么呢?

@Configuration
public class MybatisPlusConfig {
    @Bean
    public MetaObjectHandler metaObjectHandler() {
        return new MyMetaObjectHandler();
    }
}
// 自定义填充策略
public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        // 自动填充逻辑
    }
    
    @Override
    public void updateFill(MetaObject metaObject) {
        // 自动填充逻辑
    }
}
// 实体类
public class User {
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;
}
// 测试用例
@Test
public void testInsert() {
    User user = new User();
    user.setName("张三");
    userService.save(user);
    // ...
}

以上是一个简单的示例,我们在实体类的createTime字段上配置了FieldFill.INSERT策略,在updateTime字段上配置了FieldFill.INSERT_UPDATE策略。然而,当我们执行插入操作时,发现这两个字段的值都是null。这是因为在MybatisPlus的自动填充功能中,它会根据字段的类型来判断该字段是否需要填充,默认情况下,Date类型的字段是不会自动填充的。

要解决这个问题,我们需要在自定义的MetaObjectHandler中重写getMetaObjectHandler方法,并为Date类型的字段设置填充策略:

public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
    }
    
    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
    }

    @Override
    public MetaObjectHandler getMetaObjectHandler(Class<?> handlerType) {
        return MybatisDefaultMetaObjectHandler.INSTANCE;
    }
}

通过重写getMetaObjectHandler方法,返回MybatisDefaultMetaObjectHandler.INSTANCE实例,即可解决自动填充字段的值为空的问题。

问题2:自动填充字段的值不变

有时候我们会发现在更新记录时,自动填充字段的值并没有发生改变,原本期望它在更新操作时会更新为当前时间,但实际上其值还是插入时的值。这是为什么呢?

这个问题实际上是因为我们在更新操作时,并没有设置自动填充字段的更新值。在自定义的MetaObjectHandler中,我们需要重写updateFill方法,并为自动填充字段设置更新值:

public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void updateFill(MetaObject metaObject) {
        Object val = getFieldValByName("updateTime", metaObject);
        if (val == null) {
            this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
        }
    }
}

通过判断自动填充字段的值是否为空,如果为空则调用strictInsertFill方法为其设置更新值。这样就可以解决自动填充字段的值不变的问题。

问题3:自动填充字段的值覆盖

在使用自动填充功能时,我们可能会遇到一个问题,就是自动填充字段的值在插入和更新操作时会被覆盖。也就是说,如果我们在代码中手动设置了自动填充字段的值,那么在插入或更新时,自动填充字段的值会被手动设置的值覆盖掉。这是为什么呢?

这个问题是由于MyBatisPlus的自动填充功能先于SQL执行的问题导致的。当我们执行插入或更新操作时,MyBatisPlus会先执行自动填充操作,然后再执行SQL语句。而如果我们在代码中手动设置了自动填充字段的值,由于自动填充操作是先于SQL执行的,所以最终插入或更新到数据库的值仍然是自动填充的值。

要解决这个问题,我们可以通过在自定义的MetaObjectHandler中重写insertFill和updateFill方法,判断是否手动设置了自动填充字段的值,如果设置了则不进行自动填充操作:

public class MyMetaObjectHandler implements MetaObjectHandler {
    @Override
    public void insertFill(MetaObject metaObject) {
        Object val = getFieldValByName("createTime", metaObject);
        if (val == null) {
            this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
        }
    }
    
    @Override
    public void updateFill(MetaObject metaObject) {
        Object val = getFieldValByName("updateTime", metaObject);
        if (val == null) {
            this.strictInsertFill(metaObject, "updateTime", Date.class, new Date());
        }
    }
}

通过判断字段的值是否为空,如果为空则进行自动填充操作,否则不进行填充。这样就可以避免自动填充字段的值被手动设置的值覆盖的问题了。

总结:

MyBatisPlus的自动填充功能是一个很方便的特性,可以在操作数据库时减轻开发者的工作量。但在使用自动填充功能时,可能会遇到一些坑。本文介绍了几个常见的问题和解决方案,包括自动填充字段的值为空、自动填充字段的值不变以及自动填充字段的值覆盖等。通过正确地配置自定义的MetaObjectHandler,并根据需求进行相关的判断和设置,就可以解决这些问题。希望本文能帮助到大家在使用MyBatisPlus自动填充功能时更加顺利地进行开发。