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 = ?)
总结
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
相关文章
springboot在filter中如何用threadlocal存放用户身份信息
这篇文章主要介绍了springboot中在filter中如何用threadlocal存放用户身份信息,本文章主要描述通过springboot的filter类,在过滤器中设置jwt信息进行身份信息保存的方法,需要的朋友可以参考下2024-07-07使用maven一步一步构建spring mvc项目(图文详解)
这篇文章主要介绍了详解使用maven一步一步构建spring mvc项目,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2017-09-09
最新评论