解决mybatisplus MetaObjectHandler 失效的问题

 更新时间:2023年02月05日 10:53:51   作者:lilun1231  
本文主要介绍了解决mybatisplus MetaObjectHandler 失效的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、什么是metaObjectHandler

MetaObjectHandler接口是mybatisPlus为我们提供的的一个扩展接口,我们可以利用这个接口在我们插入或者更新数据的时候,为一些字段指定默认值
使用方式如下:

1、在实体类上加入@TableField注解

@Getter
@Setter
public class AbstractBaseDO<T extends Model<T>> extends Model<T> implements Serializable {

    /**
     * 创建时间 新增时填充
     */
    @TableField(fill = FieldFill.INSERT)
    private Date gmtCreate;

    /**
     * 修改时间 新增和更新时填充
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Date gmtModified;

    /**
     * 创建人ID 新增时更新
     */
    @TableField(fill = FieldFill.INSERT)
    private Long creatorId;

    /**
     * 修改人ID 新增和更新时填充
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long modifierId;

    /**
     * 逻辑删除字段 新增和更新时填充
     */
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer isDeleted;

    @Override
    public String toString() {
        return new ToStringBuilder(this)
            .append("gmtCreate", gmtCreate)
            .append("gmtModified", gmtModified)
            .append("creatorId", creatorId)
            .append("modifierId", modifierId)
            .append("isDeleted", isDeleted)
            .toString();
    }
}

2、创建配置类实现MetaObjectHandler接口

@Slf4j
@Configuration
public class MetaObjectHandlerConfig implements MetaObjectHandler {
    
    /**
    *插入时自动填充
    */
    @Override
    public void insertFill(MetaObject metaObject) {
        //获得用户上下文
        UserContext dscUser = GlobalSessionContext.getDscUser();
        //获得当前时间
        Date date = Calendar.getInstance().getTime();

        //创建时间
        this.fillStrategy(metaObject, "gmtCreate", date);
        //更新时间
        this.fillStrategy(metaObject, "gmtModified", date);
        //未删除
        this.fillStrategy(metaObject, "isDeleted", CommonConstants.NON_DELETED);
        //创建者
        this.fillStrategy(metaObject, "creatorId", dscUser.getUserId());
        //更新者
        this.fillStrategy(metaObject, "modifierId", dscUser.getUserId());

    }
    
    /**
    *修改时自动填充
    */
    @Override
    public void updateFill(MetaObject metaObject) {
        //获得用户上下文
        UserContext dscUser = GlobalSessionContext.getDscUser();
        //获得当前时间
        Date date = Calendar.getInstance().getTime();
        //强制更新时间
        this.setFieldValByName("gmtModified", date, metaObject);
        //更新者
        this.fillStrategy(metaObject, "modifierId",dscUser.getUserId());

    }
}

二、失效场景及解决方案

1、使用mybatis-plus的boolean update(Wrapper updateWrapper)链式更新方法时失效

1)示例代码

/**
*更新属性
*/
 @Override
    public Boolean expireHistoryTask(Long tenantId, Long produceInfoId) {
        return this.update(new UpdateWrapper<TaskDetailInfoDO>().lambda()
            .eq(TaskDetailInfoDO::getTenantId, tenantId)
            .in(TaskDetailInfoDO::getProduceInfoId, produceInfoId)
            .eq(TaskDetailInfoDO::getIsDeleted, CommonConstants.NON_DELETED)
            .set(TaskDetailInfoDO::getTaskStatus, TaskStatusEnum.EXPIRED.getCode())
            
    }

2)失效原因

这种更新方法失效我们需要去看mbatis-plus的源码

   private static void process(MappedStatement ms, Object parameterObject) {
        if (parameterObject != null) {
            TableInfo tableInfo = null;
            Object entity = parameterObject;
            if (parameterObject instanceof Map) {
                Map<?, ?> map = (Map<?, ?>) parameterObject;
                if (map.containsKey(Constants.ENTITY)) {
                    Object et = map.get(Constants.ENTITY);
                    if (et != null) {
                        entity = et;
                        tableInfo = TableInfoHelper.getTableInfo(entity.getClass());
                    }
                }
            } else {
                tableInfo = TableInfoHelper.getTableInfo(parameterObject.getClass());
            }
            //tableInfo为空,则不自动填充
            if (tableInfo != null) {
                //到这里就应该转换到实体参数对象了,因为填充和ID处理都是争对实体对象处理的,不用传递原参数对象下去.
                MetaObject metaObject = ms.getConfiguration().newMetaObject(entity);
                if (SqlCommandType.INSERT == ms.getSqlCommandType()) {
                    populateKeys(tableInfo, metaObject, entity);
                    insertFill(metaObject, tableInfo);
                } else {
                    updateFill(metaObject, tableInfo);
                }
            }
        }
    }

从上面的代码可以看出,当tableInfo为空,则不自动填充字段值。而继续看,tableInfo是从parameterObject中获取,而这parameterObject就是要更新的实体对象。
在看我们使用 update(Wrapper updateWrapper)更新的底层逻辑

 /**
     * 根据 UpdateWrapper 条件,更新记录 需要设置sqlset
     *
     * @param updateWrapper 实体对象封装操作类 {@link com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper}
     */
    default boolean update(Wrapper<T> updateWrapper) {
        //传入了一个空实体
        return update(null, updateWrapper);
    }

此时是传了一个空对象,这就导致了整个后续的填充都失效了。

3)解决方法

使用update的另一个方法

在更新是传入实体对象

  @Override
    public Boolean expireHistoryTask(Long tenantId, Long produceInfoId) {
        return this.update(new TaskDetailInfoDO(), new UpdateWrapper<TaskDetailInfoDO>().lambda()
            .eq(TaskDetailInfoDO::getTenantId, tenantId)
            .in(TaskDetailInfoDO::getProduceInfoId, produceInfoId)
            .eq(TaskDetailInfoDO::getIsDeleted, CommonConstants.NON_DELETED)
            .set(TaskDetailInfoDO::getTaskStatus, TaskStatusEnum.EXPIRED.getCode())
        );
    }

2、填充时使用 MetaObjectHandler fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal) 方法

 @Override
    public void updateFill(MetaObject metaObject) {
        //获得用户上下文
        UserContext dscUser = GlobalSessionContext.getDscUser();
        //更新者
        this.fillStrategy(metaObject, "modifierId", dscUser.getUserId());
    }

fillStartegy的源码时这样的

    /**
     * 填充策略,默认有值不覆盖,如果提供的值为null也不填充
     *
     * @param metaObject metaObject meta object parameter
     * @param fieldName  java bean property name
     * @param fieldVal   java bean property value of Supplier
     * @since 3.3.0
     */
    default MetaObjectHandler fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal) {
        if (getFieldValByName(fieldName, metaObject) == null) {
            setFieldValByName(fieldName, fieldVal, metaObject);
        }
        return this;
    }

当需要更新的字段已经有值时,则默认不更新。需要强制更新字段时,使用 MetaObjectHandler setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject) 方法更新字段值。

   @Override
    public void updateFill(MetaObject metaObject) {
        //获得用户上下文
        UserContext dscUser = GlobalSessionContext.getDscUser();
        //获得当前时间
        Date date = Calendar.getInstance().getTime();
        //更新时间
        this.setFieldValByName("gmtModified", date, metaObject);
        //更新者
        this.setFieldValByName("modifierId", metaObject, dscUser.getUserId());
    }

到此这篇关于解决mybatisplus MetaObjectHandler 失效的问题的文章就介绍到这了,更多相关mybatisplus MetaObjectHandler 失效内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java调用浏览器打开网页完整实例

    Java调用浏览器打开网页完整实例

    这篇文章主要介绍了Java调用浏览器打开网页的方法,以完整实例形式分析了java打开网页的相关技巧,需要的朋友可以参考下
    2015-05-05
  • java获取linux服务器上的IP操作

    java获取linux服务器上的IP操作

    这篇文章主要介绍了java获取linux服务器上的IP操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • java实现学生信息管理系统

    java实现学生信息管理系统

    这篇文章主要为大家详细介绍了java实现学生信息管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • Java 堆内存与栈内存详细介绍

    Java 堆内存与栈内存详细介绍

    这篇文章主要介绍了Java 堆内存与栈内存详细介绍的相关资料,这里对java 的堆内存和栈内存进行了详细的分析,需要的朋友可以参考下
    2016-11-11
  • Java解决青蛙跳台阶问题流程

    Java解决青蛙跳台阶问题流程

    所谓的青蛙跳台阶问题,就是指一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。本文将用Java解决这一问题,需要的可以参考一下
    2022-03-03
  • 优雅地在Java应用中实现全局枚举处理的方法

    优雅地在Java应用中实现全局枚举处理的方法

    这篇文章主要给大家介绍了关于如何优雅地在Java应用中实现全局枚举处理的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-02-02
  • Java多线程之循环栅栏技术CyclicBarrier使用探索

    Java多线程之循环栅栏技术CyclicBarrier使用探索

    这篇文章主要介绍了Java多线程之循环栅栏技术CyclicBarrier,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪<BR>
    2024-01-01
  • java多线程实现交通灯管理系统

    java多线程实现交通灯管理系统

    这篇文章主要为大家详细介绍了java多线程实现交通灯管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • Java指令重排引发问题及解决方案

    Java指令重排引发问题及解决方案

    指令重排是JVM在解释执行Java代码时对指令顺序进行重新排列的一种优化技术,本文主要介绍了Java指令重排引发问题及解决方案,感兴趣的可以了解一下
    2023-08-08
  • 详解Java的Hibernate框架中的Interceptor和Collection

    详解Java的Hibernate框架中的Interceptor和Collection

    这篇文章主要介绍了Java的Hibernate框架中的Interceptor和Collection,Hibernate是Java的SSH三大web开发框架之一,需要的朋友可以参考下
    2016-01-01

最新评论