欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

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

来源: javaer 分享于  点击 7708 次 点评:19

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 = ?)

      总结

      以上为个人经验,希望能给大家一个参考,也希望大家多多支持3672js教程。

      您可能感兴趣的文章:
      • Mybatis-Plus的条件构造器QueryWrapper & UpdateWrapper示例详解
      • Mybatis-plus批量去重插入ON DUPLICATE key update使用方式
      • mybatis-plus saveOrUpdateBatch踩坑记录
      • MyBatis-Plus updateById不更新null值的方法解决
      • Mybatis-Plus的saveOrUpdateBatch(null)问题及解决
      相关栏目:

      用户点评