首頁 > 軟體

Mybatis-plus自動填充不生效或自動填充資料為null原因及解決方案

2022-05-17 19:00:49

昨天使用mybatis-plus。使用自動填充後發現了兩個問題。

  • 一個是填充資料為null,
  • 一個是當使用了mybatis-plus的樂觀鎖,自動填充就失效了

開始在網上看,有人說是mybatis的bug,我想不會我這麼快就遇到了bug。後面我通過idea的(ctrl+B)看他的原始碼.發現這不是bug,而是一個非常巧妙的設計,當然也可能是之前有bug,我用的版本是正常的

mybatis官網自動填充功能說明
我使用的版本是3.3.2

如果想省時間,前面的問題描述和分析過程不用看,直接根據目錄跳到小結就好了。

問題一:自動填充的資料為null

原因:[填充的資料型別] 和 [實體類定義的資料型別] 不一致。例如你的updateTime是 java.util.Date型別的。但是填充的是LocalDateTime(因為官網給個就是這個,可能就是直接用了)。這就會導致填充的資料為空。

參考如下定義

this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());

以下是官網給的示範:(我把那兩個過期方法去掉了)

@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 有多個方法,詳細檢視原始碼) */
       
    }

    @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 有多個方法,詳細檢視原始碼) */
    }
}

問題二:使用mybatis-plus的樂觀鎖後發現自動填充的updateTime欄位不自動填充了

該問題還有其他描述:從資料庫查出來的資料,無法進行自動填充

本質原因:當該欄位有值之後,自動填充不進行填充,裡面的資料還是原值

下面兩段程式碼,testUpdateUser和testOptimisticLocker。前者updateTime進行了自動填充,後者沒有進行自動填充。

原因是後者的User物件所有欄位的值都從資料庫查出來,並進行了賦值。然後自動填充資料沒有填充資料

範例:

    @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());,這是官網提供的方法之一
我們ctrl+B進去看下

default MetaObjectHandler fillStrategy(MetaObject metaObject, String fieldName, Object fieldVal) {
        if (this.getFieldValByName(fieldName, metaObject) == null) {
            this.setFieldValByName(fieldName, fieldVal, metaObject);
        }

        return this;
    }

發現就是故意這樣設計的,當你要填充的欄位 fieldName對應的欄位為空時才進行自動填充,否則不進行填充
然後我又看了官網提供的另一個方法this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
ctrl+B 看下原始碼

最終呼叫的是下面這個。有點長。一看就不想看

然後我strict的意思,嚴格的。我推測這個應該就是說強制執行的意思,不管是否有原值都強制執行更新。然後我試了下,果然就是這樣的

    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;
    }

最後總結:
insert也是一樣的。

   @Override
    public void updateFill(MetaObject metaObject) {
        // 如果有值,則不會更新
       // this.fillStrategy(metaObject,"updateTime",new Date());
        // 即使有值,也更新為當前時間
       this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());

    }

小結

填充的方法一共有三個

// 這個是通用的,插入和更新都可以使用 但是當欄位存在值 的時候不進行填充
this.fillStrategy(metaObject, "createTime", LocalDateTime.now()); // 也可以使用(3.3.0 該方法有bug請升級到之後的版本如`3.3.1.8-SNAPSHOT`)
// 這個是insert的時候用的,插入的時候時候強制進行填充
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推薦使用)
// update的時候使用,更新的時候強制進行填充
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // 起始版本 3.3.0(推薦使用)

注意填充的型別,要和你定義欄位的型別一致,不然就可能出現填充為為空值的情況 例如原值是java.util.Date ,填充的LocalDateTime就會出現這種情況

到此這篇關於Mybatis-plus自動填充不生效或自動填充資料為null原因及解決方案的文章就介紹到這了,更多相關Mybatis-plus自動填充內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com