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

基于mybatis-plus timestamp返回為null問(wèn)題的排除

 更新時(shí)間:2021年08月31日 11:58:39   作者:水中加點(diǎn)糖  
這篇文章主要介紹了mybatis-plus timestamp返回為null問(wèn)題的排除,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

問(wèn)題是這樣的

在開(kāi)發(fā)時(shí),為了節(jié)約時(shí)間,我選擇了mybatis框架來(lái)開(kāi)發(fā),然后又在網(wǎng)上找了一個(gè)許多人都推薦的mybatis-plus來(lái)作為持久層框架。

于是乎我按照官方的DEMO下了一個(gè)springBoot的mybatis-plus版本的DEMO

這個(gè)DEMO是基于H2數(shù)據(jù)庫(kù)的,跑了下沒(méi)有問(wèn)題。DEMO是能正常運(yùn)行的。

然后我將這個(gè)工程的代碼快速拷貝的新的一個(gè)工程里,并把數(shù)據(jù)庫(kù)由H2換為了MYSQL。但項(xiàng)目跑起來(lái)時(shí),出現(xiàn)了如下問(wèn)題:

數(shù)據(jù)庫(kù)里的數(shù)據(jù)如下圖

表結(jié)構(gòu)如下圖

查詢(xún)出來(lái)的結(jié)果中對(duì)于timestamp類(lèi)型的字段為空

為了解決這個(gè)問(wèn)題,我決定通過(guò)debug斷點(diǎn)觀察下是否查詢(xún)是把數(shù)據(jù)數(shù)據(jù)查出來(lái)了

由于用的mybatis-plus框架來(lái)開(kāi)發(fā),而mybaits-plus框架是基于mybatis框架的,為了看是否把數(shù)據(jù)查詢(xún)出來(lái),直接在ResultSetHandler上把一個(gè)dubug就好。在默認(rèn)情況下,mybatis框架使用的ResultSetHandler為DefaultResultSetHandler,當(dāng)查詢(xún)mybatis查詢(xún)完畢后,會(huì)通過(guò)ResultSetHandler的handleResultSets(Statement stmt)方法對(duì)查詢(xún)的數(shù)據(jù)結(jié)果集進(jìn)行封裝

所以將斷點(diǎn)打在handlerResultSets方法上最為合適。

再通過(guò)statement -> wrapper ->results -> rowData ->rows觀察發(fā)現(xiàn)如下數(shù)據(jù):

查詢(xún)返回的結(jié)果集中rows的記錄數(shù)為1,第1個(gè)字段的ascii為49,而49是ascii中數(shù)字1的值。而第二個(gè)字段也有值,說(shuō)明所對(duì)應(yīng)的timestamp字段是有返回值的,數(shù)據(jù)庫(kù)查詢(xún)是沒(méi)有問(wèn)題的。

然而通過(guò)mybatis代碼進(jìn)一步封裝后的數(shù)據(jù)multipleResults又表示,只查詢(xún)到了類(lèi)型為Int的字段的數(shù)據(jù)

這么也就是說(shuō),問(wèn)題應(yīng)該是出在了multipleResults的賦值問(wèn)題上了

handleResultSets的完整代碼為

//
// HANDLE RESULT SETS
//
@Override
public List<Object> handleResultSets(Statement stmt) throws SQLException {
  ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
  final List<Object> multipleResults = new ArrayList<Object>();
  int resultSetCount = 0;
  ResultSetWrapper rsw = getFirstResultSet(stmt);
  List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  int resultMapCount = resultMaps.size();
  validateResultMapsCount(rsw, resultMapCount);
  while (rsw != null && resultMapCount > resultSetCount) {
    ResultMap resultMap = resultMaps.get(resultSetCount);
    handleResultSet(rsw, resultMap, multipleResults, null);
    rsw = getNextResultSet(stmt);
    cleanUpAfterHandlingResultSet();
    resultSetCount++;
  }
  String[] resultSets = mappedStatement.getResultSets();
  if (resultSets != null) {
    while (rsw != null && resultSetCount < resultSets.length) {
      ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
      if (parentMapping != null) {
        String nestedResultMapId = parentMapping.getNestedResultMapId();
        ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
        handleResultSet(rsw, resultMap, null, parentMapping);
      }
      rsw = getNextResultSet(stmt);
      cleanUpAfterHandlingResultSet();
      resultSetCount++;
    }
  }
  return collapseSingleResultList(multipleResults);
}

說(shuō)明問(wèn)題出在 handleResultSet(rsw, resultMap, multipleResults, null);這句代碼上了

通過(guò)代碼跟蹤,發(fā)現(xiàn)如下代碼

//
// GET VALUE FROM ROW FOR SIMPLE RESULT MAP
//
private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap) throws SQLException {
  final ResultLoaderMap lazyLoader = new ResultLoaderMap();
  Object rowValue = createResultObject(rsw, resultMap, lazyLoader, null);
  if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
    final MetaObject metaObject = configuration.newMetaObject(rowValue);
    boolean foundValues = this.useConstructorMappings;
    if (shouldApplyAutomaticMappings(resultMap, false)) {
      foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, null) || foundValues;
    }
    foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, null) || foundValues;
    foundValues = lazyLoader.size() > 0 || foundValues;
    rowValue = (foundValues || configuration.isReturnInstanceForEmptyRow()) ? rowValue : null;
  }
  return rowValue;
}

繼而發(fā)現(xiàn)如下的核心代碼

private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
  List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
  boolean foundValues = false;
  if (!autoMapping.isEmpty()) {
    for (UnMappedColumnAutoMapping mapping : autoMapping) {
      final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
      if (value != null) {
        foundValues = true;
      }
      if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
        // gcode issue #377, call setter on nulls (value is not 'found')
        metaObject.setValue(mapping.property, value);
      }
    }
  }
  return foundValues;
}

通過(guò)斷點(diǎn)發(fā)現(xiàn)以下數(shù)據(jù)

在獲取這個(gè)查詢(xún)的的返回字段時(shí),只獲取出來(lái)兩個(gè),即int類(lèi)型和varchar類(lèi)型的.

再通過(guò)跟蹤發(fā)現(xiàn)了如下代碼

private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
  final String mapKey = resultMap.getId() + ":" + columnPrefix;
  List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
  if (autoMapping == null) {
    autoMapping = new ArrayList<UnMappedColumnAutoMapping>();
    final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
    for (String columnName : unmappedColumnNames) {
      String propertyName = columnName;
      if (columnPrefix != null && !columnPrefix.isEmpty()) {
        // When columnPrefix is specified,
        // ignore columns without the prefix.
        if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
          propertyName = columnName.substring(columnPrefix.length());
        } else {
          continue;
        }
      }
      final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
      if (property != null && metaObject.hasSetter(property)) {
        if (resultMap.getMappedProperties().contains(property)) {
          continue;
        }
        final Class<?> propertyType = metaObject.getSetterType(property);
        if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {
          final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
          autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));
        } else {
          configuration.getAutoMappingUnknownColumnBehavior()
              .doAction(mappedStatement, columnName, property, propertyType);
        }
      } else {
        configuration.getAutoMappingUnknownColumnBehavior()
            .doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);
      }
    }
    autoMappingsCache.put(mapKey, autoMapping);
  }
  return autoMapping;
}

直到看到這里

final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase()); 

才知道問(wèn)題所在了, configuration.isMapUnderscoreToCamelCase()的值為true,即開(kāi)啟了駝峰命令。

所以查找字段時(shí)就找不到。 把之前的類(lèi)似crt_time改為crtTime后,就可以了! 沒(méi)想到這么一個(gè)小錯(cuò)誤,讓我糾結(jié)了這么久!還好能跟蹤源碼!

通過(guò)這次的問(wèn)題排查,讓我明白了一個(gè)道理: 如果不知道某個(gè)框架原理的情況下,不要隨便填寫(xiě)它的配置信息。在享受到框架的便捷性的同時(shí),最好也得要明白它的原理,這樣當(dāng)出現(xiàn)問(wèn)題時(shí),才好快速定位。

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

相關(guān)文章

  • Java實(shí)現(xiàn)單鏈表基礎(chǔ)操作

    Java實(shí)現(xiàn)單鏈表基礎(chǔ)操作

    大家好,本篇文章主要講的是Java實(shí)現(xiàn)單鏈表基礎(chǔ)操作,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-02-02
  • Java 獲取兩個(gè)List的交集和差集,以及應(yīng)用場(chǎng)景操作

    Java 獲取兩個(gè)List的交集和差集,以及應(yīng)用場(chǎng)景操作

    這篇文章主要介紹了Java 獲取兩個(gè)List的交集和差集,以及應(yīng)用場(chǎng)景操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • 一文掌握spring cloud gateway(總結(jié)篇)

    一文掌握spring cloud gateway(總結(jié)篇)

    Spring Cloud Gateway是Spring Cloud的全新項(xiàng)目,該項(xiàng)目是基于Spring 5.0,Spring WebFlux和Project Reactor等技術(shù)開(kāi)發(fā)的網(wǎng)關(guān),它旨在為微服務(wù)架構(gòu)提供一種簡(jiǎn)單有效的統(tǒng)一的API路由管理方式,本文通過(guò)實(shí)例代碼總結(jié)介紹spring cloud gateway的相關(guān)知識(shí),感興趣的朋友一起看看吧
    2024-12-12
  • JAVA字符串占位符使用方法實(shí)例

    JAVA字符串占位符使用方法實(shí)例

    今天同事又問(wèn)起類(lèi)似符串占位符使用的功能,所以下面這篇文章主要給大家介紹了關(guān)于JAVA字符串占位符使用的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-11-11
  • Spring Boot集成Mybatis中如何顯示日志的實(shí)現(xiàn)

    Spring Boot集成Mybatis中如何顯示日志的實(shí)現(xiàn)

    這篇文章主要介紹了Spring Boot集成Mybatis中如何顯示日志的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Spring Eureka 未授權(quán)訪問(wèn)漏洞修復(fù)問(wèn)題小結(jié)

    Spring Eureka 未授權(quán)訪問(wèn)漏洞修復(fù)問(wèn)題小結(jié)

    項(xiàng)目組使用的 Spring Boot 比較老,是 1.5.4.RELEASE ,最近被檢測(cè)出 Spring Eureka 未授權(quán)訪問(wèn)漏洞,這篇文章主要介紹了Spring Eureka 未授權(quán)訪問(wèn)漏洞修復(fù)問(wèn)題小結(jié),需要的朋友可以參考下
    2024-04-04
  • 詳解spring boot配置單點(diǎn)登錄

    詳解spring boot配置單點(diǎn)登錄

    本篇文章主要介紹了詳解spring boot配置單點(diǎn)登錄,常用的安全框架有spring security和apache shiro。shiro的配置和使用相對(duì)簡(jiǎn)單,本文使用shrio對(duì)接CAS服務(wù)。
    2017-03-03
  • SpringBoot3.x打包Docker容器的實(shí)現(xiàn)

    SpringBoot3.x打包Docker容器的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot3.x打包Docker容器的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • java Collection 之Set使用說(shuō)明

    java Collection 之Set使用說(shuō)明

    本篇文章小編為大家介紹,java Collection 之Set使用說(shuō)明。需要的朋友參考下
    2013-04-04
  • 淺談java中為什么重寫(xiě)equals后需要重寫(xiě)hashCode

    淺談java中為什么重寫(xiě)equals后需要重寫(xiě)hashCode

    今天帶各位學(xué)習(xí)一下java中為什么重寫(xiě)equals后需要重寫(xiě)hashCode,文中有非常詳細(xì)的圖文介紹及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好的幫助,需要的朋友可以參考下
    2021-05-05

最新評(píng)論

哈巴河县| 卢湾区| 金坛市| 扎鲁特旗| 浦北县| 吉隆县| 东莞市| 淳化县| 北宁市| 彭水| 长治县| 彰武县| 大余县| 饶河县| 买车| 青海省| 泰兴市| 昌吉市| 顺平县| 当雄县| 乐安县| 桂平市| 邯郸县| 白城市| 肇源县| 镇原县| 新乡市| 万荣县| 开阳县| 南召县| 徐汇区| 随州市| 彭泽县| 土默特右旗| 鸡泽县| 西青区| 房产| 宁南县| 河间市| 阿克陶县| 榕江县|