mybatis-plus調(diào)用update方法時(shí),自動(dòng)填充字段不生效問題及解決
項(xiàng)目場景
做定時(shí)任務(wù),查詢出數(shù)據(jù)后,將他發(fā)往mq隊(duì)列,如果搭建集群相同的數(shù)據(jù)就會(huì)執(zhí)行多次,所以使用樂觀鎖解決,同時(shí)需要更改更新時(shí)間一列,直接使用mybatisPlus的公共字段填充和樂觀鎖
問題描述
配置好mp的樂觀鎖和公共字段填充后,執(zhí)行update語句,正常應(yīng)該是
UPDATE tb_task SET update_time=?,version=? WHERE (version = ? AND id = ?)
結(jié)果變成了
UPDATE tb_task SET WHERE (version = ? AND id = ?)
因?yàn)槌诉@兩個(gè)字段沒有其他需要修改的字段所以直接就報(bào)錯(cuò)了,這么一看肯定是樂觀鎖和公共字段填充都失效了啊。
@Scheduled(cron = "0 0/1 * * * ?")
public void addCourseTask(){
//查詢1分鐘之前的數(shù)據(jù)
List<TbTask> list = tbTaskService.findBeforeMinuteList();
for (TbTask tbTask : list) {
//根據(jù)id version修改
LambdaUpdateWrapper<TbTask> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(TbTask::getId,tbTask.getId());
//.set(TbTask::getVersion,tbTask.getVersion()+1);
//數(shù)據(jù)庫中的樂觀鎖, 防止集群下的訂單,重復(fù)向mq中發(fā)送數(shù)據(jù)
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.實(shí)現(xiàn)MetaObjectHandler的公共填充類
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
//mp執(zhí)行添加操作,這個(gè)方法執(zhí)行
@Override
public void insertFill(MetaObject metaObject) {
metaObject.setValue("createTime",new Date());
metaObject.setValue("updateTime",new Date());
}
//mp執(zhí)行修改操作,這個(gè)方法執(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;
經(jīng)過查找資料后發(fā)現(xiàn)使用boolean update(Wrapper updateWrapper)這個(gè)方法,自動(dòng)填充會(huì)失效
大概原理就是boolean update(Wrapper updateWrapper)的底層實(shí)現(xiàn)為:
default boolean update(Wrapper<T> updateWrapper) {
return this.update((Object)null, updateWrapper);
}
而屬性自動(dòng)填充需要從第一個(gè)參數(shù)獲取Object實(shí)體類,自動(dòng)填充的核心方法:populateKeys中會(huì)判斷
if (null == tableInfo) {
/* 不處理 */
return parameterObject;
}
tableInfo就是獲取的實(shí)體類對象,所以導(dǎo)致屬性自動(dòng)填充失效。
解決方案
我使用的是上面文章建議的方案一,也是最簡單的方式:
使用update的重載方法
boolean update(T entity, Wrapper updateWrapper)
修改后的代碼如下:
@Scheduled(cron = "0 0/1 * * * ?")
public void addCourseTask(){
//查詢1分鐘之前的數(shù)據(jù)
List<TbTask> list = tbTaskService.findBeforeMinuteList();
for (TbTask tbTask : list) {
//根據(jù)id version修改
LambdaUpdateWrapper<TbTask> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(TbTask::getId,tbTask.getId());
//.set(TbTask::getVersion,tbTask.getVersion()+1);
//數(shù)據(jù)庫中的樂觀鎖, 防止集群下的訂單,重復(fù)向mq中發(fā)送數(shù)據(jù)
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 = ?)
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- MyBatisPlus實(shí)現(xiàn)自動(dòng)填充字段的實(shí)踐
- MyBatis-Plus自動(dòng)填充字段的詳細(xì)教程
- MyBatis-Puls插入或修改時(shí)某些字段自動(dòng)填充操作示例
- Mybatis-Plus實(shí)現(xiàn)公共字段自動(dòng)填充的項(xiàng)目實(shí)踐
- MyBatis-Plus邏輯刪除和字段自動(dòng)填充的實(shí)現(xiàn)
- MyBatis-Plus實(shí)現(xiàn)公共字段自動(dòng)填充功能詳解
- Mybatis-Plus自動(dòng)填充更新操作相關(guān)字段的實(shí)現(xiàn)
- MyBatis-Plus實(shí)現(xiàn)字段自動(dòng)填充功能的示例
- Mybatis plus通用字段自動(dòng)填充的示例
- Mybatis攔截器實(shí)現(xiàn)公共字段填充的示例代碼
相關(guān)文章
Springboot中動(dòng)態(tài)語言groovy介紹
Apache的Groovy是Java平臺(tái)上設(shè)計(jì)的面向?qū)ο缶幊陶Z言,這門動(dòng)態(tài)語言擁有類似Python、Ruby和Smalltalk中的一些特性,可以作為Java平臺(tái)的腳本語言使用,這篇文章主要介紹了springboot中如何使用groovy,需要的朋友可以參考下2022-09-09
SpringBoot中的異常處理與參數(shù)校驗(yàn)的方法實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot中的異常處理與參數(shù)校驗(yàn)的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
SpringBoot+Nacos+Kafka微服務(wù)流編排的簡單實(shí)現(xiàn)
本文主要介紹了SpringBoot+Nacos+Kafka微服務(wù)流編排的簡單實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
基于Properties實(shí)現(xiàn)配置數(shù)據(jù)庫驅(qū)動(dòng)
這篇文章主要介紹了基于Properties實(shí)現(xiàn)配置數(shù)據(jù)庫驅(qū)動(dòng),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05
深度解析SpringBoot中@Async引起的循環(huán)依賴
本文主要介紹了深度解析SpringBoot中@Async引起的循環(huán)依賴,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
Spring Cloud超詳細(xì)i講解Feign自定義配置與使用
這篇文章主要介紹了SpringCloud Feign自定義配置與使用,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06

