mybatis-plus調用update方法時,自動填充字段不生效問題及解決
項目場景
做定時任務,查詢出數據后,將他發(fā)往mq隊列,如果搭建集群相同的數據就會執(zhí)行多次,所以使用樂觀鎖解決,同時需要更改更新時間一列,直接使用mybatisPlus的公共字段填充和樂觀鎖
問題描述
配置好mp的樂觀鎖和公共字段填充后,執(zhí)行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中發(fā)送數據 if (tbTaskService.update(wrapper)) { String mqExchange = tbTask.getMqExchange(); String mqRoutingkey = tbTask.getMqRoutingkey(); //向mq發(fā)送消息 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執(zhí)行添加操作,這個方法執(zhí)行 @Override public void insertFill(MetaObject metaObject) { metaObject.setValue("createTime",new Date()); metaObject.setValue("updateTime",new Date()); } //mp執(zhí)行修改操作,這個方法執(zhí)行 @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;
經過查找資料后發(fā)現使用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中發(fā)送數據 if (tbTaskService.update(tbTask,wrapper)) { String mqExchange = tbTask.getMqExchange(); String mqRoutingkey = tbTask.getMqRoutingkey(); //向mq發(fā)送消息 rabbitTemplate.convertAndSend(mqExchange, mqRoutingkey, JSON.toJSONString(tbTask)); } } }
執(zhí)行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+Nacos+Kafka微服務流編排的簡單實現
本文主要介紹了SpringBoot+Nacos+Kafka微服務流編排的簡單實現,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08深度解析SpringBoot中@Async引起的循環(huán)依賴
本文主要介紹了深度解析SpringBoot中@Async引起的循環(huán)依賴,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02Spring Cloud超詳細i講解Feign自定義配置與使用
這篇文章主要介紹了SpringCloud Feign自定義配置與使用,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-06-06