最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

MybatisPlus字段自動填充失效,填充值為null的解決方案

 更新時間:2024年01月13日 09:23:36   作者:庸人沖  
這篇文章主要介紹了MybatisPlus字段自動填充失效,填充值為null的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

問題描述

有一個實體類UserEntity 對其屬性 UserEntity#createTime 字段注解了 @TableField(fill = FieldFill.INSERT)

image-20220521091544321

根據(jù)業(yè)務(wù)需要定義了 UserMapper#inserUser() 方法,參數(shù)注解了 @Param(“user”) 如下:

image-20220521091425353

當調(diào)用該方法時,無法給 createTime 字段自動填充值,報錯信息如下:

### Cause: java.sql.SQLIntegrityConstraintViolationException: Column 'create_time' cannot be null<LF>; Column 'create_time' cannot be null; nested exception is java.sql.SQLIntegrityConstraintViolationException: Column 'create_time' cannot be null]

問題剖析

在檢查了 MetaObjectHandler 實現(xiàn)類的重寫的方法無誤后,開始嘗試跟蹤 Mybatis-plus 的源碼。

發(fā)現(xiàn)在 MybatisParameterHandler#process() 中完成了自動填充的功能,在自動填充前需要先獲取 tableInfo 信息:

image-20220521093717931

而這個 TableInfoHelper.getTableInfo() 方法只有當傳入的 Class 對象是實體類對象時才能獲取到 tableInfo :

image-20220521094104208

那么問題來了,我的參數(shù)確實是實體類,但是為什么獲取不到 TableInfo 呢?

因為 MybatisParameterHandler#process() 方法的 parameter 參數(shù)在調(diào)用我自定義的方法時,傳入的是一個 Map ,這個 Mapkey 是一個字符串表示,而 value 是我自定義方法的參數(shù)實例,可以看到下圖中我的 Map 有兩個 Entry 一個 key=user 一個 key=param1

image-20220521094353846

而最為重要的是,在這個 process() 方法中,如果傳入的是一個 Map,Mybatis-plus 會從其中取 key="et" 的值,這就是問題的原因所在?。。?/p>

image-20220521094759755

而傳入的這個 Map 不存在 key="et" 的映射關(guān)系。因此兩個 TableInfoHelper.getTableInfo() 方法都進不去,所以也就不會進行自動填充。

image-20220521095247096

那么如何建立 "et" -> entity 的映射關(guān)系呢?我們Map中原本的兩個的映射關(guān)系又是從哪里來的?

根據(jù)方法的調(diào)用鏈,一直回退到 Mybatis 框架中的 MapperMethod#execute() 方法中的一行代碼:

image-20220521095621950

上面的 convertArgsToSqlCommandParam() 方法就是通過我們方法的實際參數(shù) args 轉(zhuǎn)換為執(zhí)行 sql 語句需要的參數(shù)格式,而返回值 param 就是之前傳入的那個 map

我們跟蹤該方法的調(diào)用鏈,發(fā)現(xiàn)最終調(diào)用了 ParamNameResolver#getNamedParams() 方法,該方法有3個分支,決定了我們最終得到參數(shù)是怎樣的,源碼如下:

  public Object getNamedParams(Object[] args) {
    final int paramCount = names.size();
     // 1. 方法是空參時直接返回
    if (args == null || paramCount == 0) {  
      return null;
    } else if (!hasParamAnnotation && paramCount == 1) { 
       // 2. 方法的參數(shù)沒有注解 @Param 并且只有一個參數(shù)時,直接返回這個參數(shù)實例
      Object value = args[names.firstKey()];
      return wrapToMapIfCollection(value, useActualParamName ? names.get(0) : null);
    } else {
        // 3. 否則,就建立映射關(guān)系(要么注解了 @Param,要么就是多個參數(shù))
      final Map<String, Object> param = new ParamMap<>();
      int i = 0;
        // 遍歷  names 中每一個 entry, 這個 names 是一個 sortedMap,該 Map 會保存方法參數(shù)的索引 -> 參數(shù)名稱的映射關(guān)系,如果參數(shù)注解了 @Param,則值時 @Param("xxx") 中的 xxx,如果沒有注解 @Param 則值也為參數(shù)索引,例如:
        // aMethod(@Param("M") int a, @Param("N") int b) -> {{0, "M"}, {1, "N"}}
		// aMethod(int a, int b) -> {{0, "0"}, {1, "1"}}
      for (Map.Entry<Integer, String> entry : names.entrySet()) {
          // key = 參數(shù)名稱(@Param("xxx"))或 參數(shù)的索引
          // value = 參數(shù)實例
        param.put(entry.getValue(), args[entry.getKey()]);
        
         // add generic param names (param1, param2, ...)
         // 下面就是添加 "paramN" -> 參數(shù)實例的映射,我們知道在 mapper 文件中可以使用 #{paramN} 來獲取參數(shù)列表的值,這就是原因。
        final String genericParamName = GENERIC_NAME_PREFIX + (i + 1);
        // ensure not to overwrite parameter named with @Param
        if (!names.containsValue(genericParamName)) {
          param.put(genericParamName, args[entry.getKey()]);
        }
        i++;
      }
      return param;
    }
  }

那么顯然,本次調(diào)用返回的 param 如下:

image-20220521101650953

解決方法

通過上面的分析,我們就知道了為什么咱們傳給 MybatisParameterHandler#process() 的參數(shù)是一個 Map,并且也知道了為什么自動填充失敗的根本原因,那么解決方法也就很明確了:

給實體類參數(shù)注解為 @Param(“et”),修改后記得 Mapper 文件中占位符中也要改成 #{et.property}

image-20220521102147149

或者方法只有一個實體類參數(shù)時就別標注 @Param 注解了,這樣返回的就是實體類的實例而不是一個 Map,同樣記得 Mapper 文件中占位符直接寫屬性 #{property} 即可。

image-20220521103258068

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Springboot集成Jasypt實現(xiàn)配置文件加密的方法

    Springboot集成Jasypt實現(xiàn)配置文件加密的方法

    Jasypt是一個java庫,它允許開發(fā)員以最少的努力為他/她的項目添加基本的加密功能,并且不需要對加密工作原理有深入的了解,這篇文章主要介紹了Springboot集成Jasypt實現(xiàn)配置文件加密,需要的朋友可以參考下
    2023-04-04
  • Java動態(tài)循環(huán)隊列是如何實現(xiàn)的

    Java動態(tài)循環(huán)隊列是如何實現(xiàn)的

    今天帶大家學習java隊列的相關(guān)知識,文章圍繞著如何實現(xiàn)Java動態(tài)循環(huán)隊列展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 不了解這12個語法糖,別說你會Java

    不了解這12個語法糖,別說你會Java

    這篇文章主要介紹了不了解這12個語法糖,別說你會Java,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • 深入理解Spring Cloud Zuul過濾器

    深入理解Spring Cloud Zuul過濾器

    這篇文章主要給大家介紹了關(guān)于Spring Cloud Zuul過濾器的相關(guān)資料,通過閱讀本文您將了解:Zuul過濾器類型與請求生命周期、如何編寫Zuul過濾器、如何禁用Zuul過濾器和Spring Cloud為Zuul編寫的過濾器及其功能,需要的朋友可以參考下。
    2017-02-02
  • 解決Spring國際化文案占位符失效問題的方法

    解決Spring國際化文案占位符失效問題的方法

    本篇文章主要介紹了解決Spring國際化文案占位符失效問題的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • Java手寫線程池的實現(xiàn)方法

    Java手寫線程池的實現(xiàn)方法

    這篇文章主要為大家詳細介紹了Java手寫線程池的實現(xiàn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • SSH框架網(wǎng)上商城項目第8戰(zhàn)之查詢和刪除商品類別功能實現(xiàn)

    SSH框架網(wǎng)上商城項目第8戰(zhàn)之查詢和刪除商品類別功能實現(xiàn)

    SSH框架網(wǎng)上商城項目第8戰(zhàn)之查詢和刪除商品類別功能實現(xiàn),為項目增加功能,添加、更新、刪除和查詢操作,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Java用遞歸方法解決漢諾塔問題詳解

    Java用遞歸方法解決漢諾塔問題詳解

    漢諾塔問題是一個經(jīng)典的問題。漢諾塔(Hanoi?Tower),又稱河內(nèi)塔,源于印度一個古老傳說。本文將用Java遞歸方法求解這一問題,感興趣的可以學習一下
    2022-04-04
  • java通過DelayQueue實現(xiàn)延時任務(wù)

    java通過DelayQueue實現(xiàn)延時任務(wù)

    本文主要介紹了java通過DelayQueue實現(xiàn)延時任務(wù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07
  • Jackson自定義序列化與反序列化注解詳解

    Jackson自定義序列化與反序列化注解詳解

    這篇文章主要介紹了Jackson自定義序列化與反序列化注解詳解,某些場景下,我們使用Jackson對數(shù)據(jù)進行序列化或反序列化的時候,需要對某些數(shù)據(jù)進行特殊處理,需要的朋友可以參考下
    2023-11-11

最新評論

祁连县| 武威市| 霍林郭勒市| 科技| 苍溪县| 尤溪县| 渝北区| 昆山市| 会宁县| 漳浦县| 平邑县| 德江县| 攀枝花市| 宿州市| 莱芜市| 商水县| 遂宁市| 蒲城县| 年辖:市辖区| 怀仁县| 永昌县| 水城县| 东乡县| 阳谷县| 普陀区| 漾濞| 洱源县| 永春县| 广宗县| 泾阳县| 五莲县| 阳泉市| 漯河市| 台前县| 桓仁| 苍山县| 定西市| 双城市| 韶山市| 曲阳县| 阜阳市|