Mybatis-plus自動填充不生效或自動填充數(shù)據(jù)為null原因及解決方案
昨天使用mybatis-plus。使用自動填充后發(fā)現(xiàn)了兩個問題。
- 一個是填充數(shù)據(jù)為null,
- 一個是當(dāng)使用了mybatis-plus的樂觀鎖,自動填充就失效了
開始在網(wǎng)上看,有人說是mybatis的bug,我想不會我這么快就遇到了bug。后面我通過idea的(ctrl+B)看他的源碼.發(fā)現(xiàn)這不是bug,而是一個非常巧妙的設(shè)計,當(dāng)然也可能是之前有bug,我用的版本是正常的
mybatis官網(wǎng)自動填充功能說明
我使用的版本是3.3.2
如果想省時間,前面的問題描述和分析過程不用看,直接根據(jù)目錄跳到小結(jié)就好了。
問題一:自動填充的數(shù)據(jù)為null
原因:[填充的數(shù)據(jù)類型] 和 [實體類定義的數(shù)據(jù)類型] 不一致。例如你的updateTime是 java.util.Date類型的。但是填充的是LocalDateTime(因為官網(wǎng)給個就是這個,可能就是直接用了)。這就會導(dǎo)致填充的數(shù)據(jù)為空。
參考如下定義
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
以下是官網(wǎng)給的示范:(我把那兩個過期方法去掉了)
@Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { ? ? @Override ? ? public void insertFill(MetaObject metaObject) { ? ? ? ? log.info("start insert fill ...."); ? ? ? ? this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推薦使用) ? ? ? ? this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 該方法有bug請升級到之后的版本如`3.3.1.8-SNAPSHOT`) ? ? ? ? /* 上面選其一使用,下面的已過時(注意 strictInsertFill 有多個方法,詳細(xì)查看源碼) */ ? ? ? ? ? ? } ? ? @Override ? ? public void updateFill(MetaObject metaObject) { ? ? ? ? log.info("start update fill ...."); ? ? ? ? this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推薦使用) ? ? ? ? this.fillStrategy(metaObject, "updateTime", LocalDateTime.now()); // 也可以使用(3.3.0 該方法有bug請升級到之后的版本如`3.3.1.8-SNAPSHOT`) ? ? ? ? /* 上面選其一使用,下面的已過時(注意 strictUpdateFill 有多個方法,詳細(xì)查看源碼) */ ? ? } }
問題二:使用mybatis-plus的樂觀鎖后發(fā)現(xiàn)自動填充的updateTime字段不自動填充了
該問題還有其他描述:從數(shù)據(jù)庫查出來的數(shù)據(jù),無法進(jìn)行自動填充
本質(zhì)原因:當(dāng)該字段有值之后,自動填充不進(jìn)行填充,里面的數(shù)據(jù)還是原值
下面兩段代碼,testUpdateUser和testOptimisticLocker。前者updateTime進(jìn)行了自動填充,后者沒有進(jìn)行自動填充。
原因是后者的User對象所有字段的值都從數(shù)據(jù)庫查出來,并進(jìn)行了賦值。然后自動填充數(shù)據(jù)沒有填充數(shù)據(jù)
示例:
@Test public void testUpdateUser(){ User user = new User(); user.setId(7L); user.setName("喻文波"); int rows = userMapper.updateById(user); System.out.println(rows); } /** * 測試樂觀鎖 */ @Test public void testOptimisticLocker(){ // 先查詢一個用戶 User user = userMapper.selectById(8L); System.out.println(user); // 修改用戶觀察version是否更新 user.setName("pdd"); user.setEmail("PDD@163.com"); int rows = userMapper.updateById(user); System.out.println(rows); }
原因:
填充用的方法是:this.fillStrategy(metaObject,"updateTime",new Date());,這是官網(wǎng)提供的方法之一
我們ctrl+B進(jìn)去看下
default MetaObjectHandler fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal) { ? ? ? ? if (this.getFieldValByName(fieldName, metaObject) == null) { ? ? ? ? ? ? this.setFieldValByName(fieldName, fieldVal, metaObject); ? ? ? ? } ? ? ? ? return this; ? ? }
發(fā)現(xiàn)就是故意這樣設(shè)計的,當(dāng)你要填充的字段 fieldName對應(yīng)的字段為空時才進(jìn)行自動填充,否則不進(jìn)行填充
然后我又看了官網(wǎng)提供的另一個方法this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
ctrl+B 看下源碼
最終調(diào)用的是下面這個。有點長。一看就不想看
然后我strict的意思,嚴(yán)格的。我推測這個應(yīng)該就是說強制執(zhí)行的意思,不管是否有原值都強制執(zhí)行更新。然后我試了下,果然就是這樣的
? ? default MetaObjectHandler strictFill(boolean insertFill, TableInfo tableInfo, MetaObject metaObject, List<StrictFill> strictFills) { ? ? ? ? if (insertFill && tableInfo.isWithInsertFill() || !insertFill && tableInfo.isWithUpdateFill()) { ? ? ? ? ? ? strictFills.forEach((i) -> { ? ? ? ? ? ? ? ? String fieldName = i.getFieldName(); ? ? ? ? ? ? ? ? tableInfo.getFieldList().stream().filter((j) -> { ? ? ? ? ? ? ? ? ? ? return j.getProperty().equals(fieldName) && i.getFieldType().equals(j.getPropertyType()) && (insertFill && j.isWithInsertFill() || !insertFill && j.isWithUpdateFill()); ? ? ? ? ? ? ? ? }).findFirst().ifPresent((j) -> { ? ? ? ? ? ? ? ? ? ? this.strictFillStrategy(metaObject, fieldName, i.getFieldVal()); ? ? ? ? ? ? ? ? }); ? ? ? ? ? ? }); ? ? ? ? } ? ? ? ? return this; ? ? }
最后總結(jié):
insert也是一樣的。
? ?@Override ? ? public void updateFill(MetaObject metaObject) { ? ? ? ? // 如果有值,則不會更新 ? ? ? ?// this.fillStrategy(metaObject,"updateTime",new Date()); ? ? ? ? // 即使有值,也更新為當(dāng)前時間 ? ? ? ?this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date()); ? ? }
小結(jié)
填充的方法一共有三個
// 這個是通用的,插入和更新都可以使用 但是當(dāng)字段存在值 的時候不進(jìn)行填充 this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 該方法有bug請升級到之后的版本如`3.3.1.8-SNAPSHOT`) // 這個是insert的時候用的,插入的時候時候強制進(jìn)行填充 this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推薦使用) // update的時候使用,更新的時候強制進(jìn)行填充 this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推薦使用)
注意填充的類型,要和你定義字段的類型一致,不然就可能出現(xiàn)填充為為空值的情況 例如原值是java.util.Date ,填充的LocalDateTime就會出現(xiàn)這種情況
到此這篇關(guān)于Mybatis-plus自動填充不生效或自動填充數(shù)據(jù)為null原因及解決方案的文章就介紹到這了,更多相關(guān)Mybatis-plus自動填充內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于postman傳參的幾種格式 list,map 等
這篇文章主要介紹了postman傳參的幾種格式 list,map等,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08Spring Boot整合Spring Cache及Redis過程解析
這篇文章主要介紹了Spring Boot整合Spring Cache及Redis過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-12-12