欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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" 的值,這就是問題的原因所在?。?!

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)文章

  • 基于自定義校驗注解(controller、method、(groups)分組的使用)

    基于自定義校驗注解(controller、method、(groups)分組的使用)

    這篇文章主要介紹了基于自定義校驗注解(controller、method、(groups)分組的使用),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • centos7安裝java的多種方式總結(jié)

    centos7安裝java的多種方式總結(jié)

    這篇文章主要給大家介紹了關(guān)于centos7安裝java的多種方式,文中通過實例代碼以及圖文介紹的非常詳細,對大家學習或者使用java具有一定的參考學習價值,需要的朋友可以參考下
    2023-01-01
  • 詳解SpringBoot應用服務(wù)啟動與安全終止

    詳解SpringBoot應用服務(wù)啟動與安全終止

    這篇文章主要介紹了SpringBoot應用服務(wù)啟動與安全終止,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • 詳解Spring整合Quartz實現(xiàn)動態(tài)定時任務(wù)

    詳解Spring整合Quartz實現(xiàn)動態(tài)定時任務(wù)

    本篇文章主要介紹了詳解Spring整合Quartz實現(xiàn)動態(tài)定時任務(wù),具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-03-03
  • Mybatis Plus select 實現(xiàn)只查詢部分字段

    Mybatis Plus select 實現(xiàn)只查詢部分字段

    這篇文章主要介紹了Mybatis Plus select 實現(xiàn)只查詢部分字段的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java中ByteArrayInputStream和ByteArrayOutputStream用法詳解

    Java中ByteArrayInputStream和ByteArrayOutputStream用法詳解

    這篇文章主要介紹了Java中ByteArrayInputStream和ByteArrayOutputStream用法詳解,?ByteArrayInputStream?的內(nèi)部額外的定義了一個計數(shù)器,它被用來跟蹤?read()?方法要讀取的下一個字節(jié)
    2022-06-06
  • Java字節(jié)碼指令集的使用詳細

    Java字節(jié)碼指令集的使用詳細

    本篇文章對Java字節(jié)碼指令集的使用進行了詳細的介紹。需要的朋友參考下
    2013-05-05
  • SpringBoot實現(xiàn)AOP切面的三種方式

    SpringBoot實現(xiàn)AOP切面的三種方式

    Spring,SpringBoot框架憑借多種高效機制,顯著增強了代碼的功能性,并實現(xiàn)了切面編程(AOP)的精髓,其核心亮點之一,是運用動態(tài)代理技術(shù),無需觸動源代碼即可在Bean的運行時為其動態(tài)織入額外功能,本文給大家介紹了SpringBoot通過3種方式實現(xiàn)AOP切面,需要的朋友可以參考下
    2024-08-08
  • java枚舉轉(zhuǎn)list通用類過程

    java枚舉轉(zhuǎn)list通用類過程

    文章介紹了如何將Java枚舉類型轉(zhuǎn)換為List<Map<String, Object>>的通用類,該類可以實現(xiàn)枚舉到列表的轉(zhuǎn)換,并且示例了使用方法
    2025-03-03
  • Java設(shè)計模式之中介模式

    Java設(shè)計模式之中介模式

    這篇文章主要介紹了Java設(shè)計模式之中介模式,中介模式(Mediator?Pattern),屬于行為型設(shè)計模式,目的是把系統(tǒng)中對象之間的調(diào)用關(guān)系從一對多轉(zhuǎn)變成一對一的調(diào)用關(guān)系,以此來降低多個對象和類之間的通信復雜性,需要的朋友可以參考下
    2023-12-12

最新評論