mybatis-plus调用update方法时,自动填充字段不生效问题及解决

 更新时间:2024年06月05日 10:59:54   作者:远离bug,珍爱头发  
这篇文章主要介绍了mybatis-plus调用update方法时,自动填充字段不生效问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

项目场景

做定时任务,查询出数据后,将他发往mq队列,如果搭建集群相同的数据就会执行多次,所以使用乐观锁解决,同时需要更改更新时间一列,直接使用mybatisPlus的公共字段填充和乐观锁

问题描述

配置好mp的乐观锁和公共字段填充后,执行update语句,正常应该是

UPDATE tb_task SET update_time=?,version=? WHERE (version = ? AND id = ?)

结果变成了

UPDATE tb_task SET WHERE (version = ? AND id = ?)

因为除了这两个字段没有其他需要修改的字段所以直接就报错了,这么一看肯定是乐观锁和公共字段填充都失效了啊。

@Scheduled(cron = "0 0/1 * * * ?")
    public void addCourseTask(){
        //查询1分钟之前的数据
        List<TbTask> list = tbTaskService.findBeforeMinuteList();
        for (TbTask tbTask : list) {
            //根据id version修改
            LambdaUpdateWrapper<TbTask> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(TbTask::getId,tbTask.getId());
                    //.set(TbTask::getVersion,tbTask.getVersion()+1);
            //数据库中的乐观锁, 防止集群下的订单,重复向mq中发送数据
            if (tbTaskService.update(wrapper)) {
                String mqExchange = tbTask.getMqExchange();
                String mqRoutingkey = tbTask.getMqRoutingkey();
                //向mq发送消息
                rabbitTemplate.convertAndSend(mqExchange, mqRoutingkey, JSON.toJSONString(tbTask));

            }


        }
    }

原因分析

检查了几遍确定mp的乐观锁和公共字段填充都没有问题

乐观锁

1.配置乐观锁插件(mp是3.5.1的)

@Configuration
@MapperScan("com.xly.mapper") //扫描mapper接口所在包
public class MybatisPlusConfig {

    @Bean
    //配置分页插件
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //分页
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        //乐观锁
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;

    }
}

2.字段上打注解

@TableField(value = "version")
    @Version
    private Integer version;

公共字段填充

1.实现MetaObjectHandler的公共填充类

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
    //mp执行添加操作,这个方法执行
    @Override
    public void insertFill(MetaObject metaObject) {
        metaObject.setValue("createTime",new Date());
        metaObject.setValue("updateTime",new Date());
    }

    //mp执行修改操作,这个方法执行
    @Override
    public void updateFill(MetaObject metaObject) {
        metaObject.setValue("updateTime",new Date());
    }
}

2.在字段上添加fill属性

@TableField(value = "create_time",fill = FieldFill.INSERT)
    private Date createTime;
    @TableField(value = "update_time",fill = FieldFill.INSERT_UPDATE)
    private Date updateTime;

经过查找资料后发现使用boolean update(Wrapper updateWrapper)这个方法,自动填充会失效

大概原理就是boolean update(Wrapper updateWrapper)的底层实现为:

default boolean update(Wrapper<T> updateWrapper) {
        return this.update((Object)null, updateWrapper);
    }

而属性自动填充需要从第一个参数获取Object实体类,自动填充的核心方法:populateKeys中会判断

if (null == tableInfo) {
            /* 不处理 */
            return parameterObject;
        }

tableInfo就是获取的实体类对象,所以导致属性自动填充失效。

解决方案

我使用的是上面文章建议的方案一,也是最简单的方式:

使用update的重载方法

boolean update(T entity, Wrapper updateWrapper)

修改后的代码如下:

@Scheduled(cron = "0 0/1 * * * ?")
    public void addCourseTask(){
        //查询1分钟之前的数据
        List<TbTask> list = tbTaskService.findBeforeMinuteList();
        for (TbTask tbTask : list) {
            //根据id version修改
            LambdaUpdateWrapper<TbTask> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(TbTask::getId,tbTask.getId());
                    //.set(TbTask::getVersion,tbTask.getVersion()+1);
            //数据库中的乐观锁, 防止集群下的订单,重复向mq中发送数据
            if (tbTaskService.update(tbTask,wrapper)) {
                String mqExchange = tbTask.getMqExchange();
                String mqRoutingkey = tbTask.getMqRoutingkey();
                //向mq发送消息
                rabbitTemplate.convertAndSend(mqExchange, mqRoutingkey, JSON.toJSONString(tbTask));

            }


        }
    }

执行sql语句:

UPDATE tb_task
SET create_time=?, update_time=?, delete_time=?, task_type=?, mq_exchange=?, mq_routingkey=?, request_body=?, status=?, version=? WHERE (version = ? AND id = ?)

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Spring boot2.0 实现日志集成的方法(2)

    Spring boot2.0 实现日志集成的方法(2)

    这篇文章主要介绍了Spring boot2.0 实现日志集成的方法,上一章讲解了spring boot日志简单集成,这篇我们将日志进行分类,常规日志、异常日志、监控日志等,需要将日志输出到不同的文件,具体内容需要的小伙伴可以参考一下
    2022-04-04
  • 带你了解Java中的异常处理(上)

    带你了解Java中的异常处理(上)

    这篇文章主要介绍了Java异常处理的相关资料,帮助大家更好的理解和学习java,感兴趣的朋友可以了解下
    2020-08-08
  • springboot在filter中如何用threadlocal存放用户身份信息

    springboot在filter中如何用threadlocal存放用户身份信息

    这篇文章主要介绍了springboot中在filter中如何用threadlocal存放用户身份信息,本文章主要描述通过springboot的filter类,在过滤器中设置jwt信息进行身份信息保存的方法,需要的朋友可以参考下
    2024-07-07
  • java实现的顺时针/逆时针打印矩阵操作示例

    java实现的顺时针/逆时针打印矩阵操作示例

    这篇文章主要介绍了java实现的顺时针/逆时针打印矩阵操作,涉及java基于数组的矩阵存储、遍历、打印输出等相关操作技巧,需要的朋友可以参考下
    2019-12-12
  • Java文件上传下载、邮件收发实例代码

    Java文件上传下载、邮件收发实例代码

    这篇文章主要介绍了Java文件上传下载、邮件收发实例代码的相关资料,非常不错具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • Java多态(动力节点Java学院整理)

    Java多态(动力节点Java学院整理)

    多态是指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。接下来通过本文给大家介绍java多态相关知识,感兴趣的朋友一起学习吧
    2017-04-04
  • 使用maven一步一步构建spring mvc项目(图文详解)

    使用maven一步一步构建spring mvc项目(图文详解)

    这篇文章主要介绍了详解使用maven一步一步构建spring mvc项目,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • 如何基于sqlite实现kafka延时消息详解

    如何基于sqlite实现kafka延时消息详解

    这篇文章主要给大家介绍了关于如何基于sqlite实现kafka延时消息的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-01-01
  • java实现读取、删除文件夹下的文件

    java实现读取、删除文件夹下的文件

    本文给大家分享的是java实现读取、删除文件夹下的文件,其中File.delete()用于删除“某个文件或者空目录”!所以要删除某个目录及其中的所有文件和子目录,要进行递归删除,有需要的小伙伴可以参考下。
    2015-05-05
  • spring security4 添加验证码的示例代码

    spring security4 添加验证码的示例代码

    本篇文章主要介绍了spring security4 添加验证码的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02

最新评论