mybatis-plus timestamp返回为null问题排除

红太狼 2022-06-01 11:16 295阅读 0赞

问题是这样的:

在开发时,为了节约时间,我选择了mybatis框架来开发,然后又在网上找了一个许多人都推荐的mybatis-plus来作为持久层框架。

于是乎我按照官方的DEMO下了一个springBoot的mybatis-plus版本的DEMO,地址为:https://gitee.com/baomidou/mybatisplus-spring-boot

这个DEMO是基于H2数据库的,跑了下没有问题。DEMO是能正常运行的。

然后我将这个工程的代码快速拷贝的新的一个工程里,并把数据库由H2换为了MYSQL。但项目跑起来时,出现了如下问题:

数据库里的数据如下图:

SouthEast

表结构如下图:

SouthEast 1

查询出来的结果中对于timestamp类型的字段为空

SouthEast 2

为了解决这个问题,我决定通过debug断点观察下是否查询是把数据数据查出来了

由于用的mybatis-plus框架来开发,而mybaits-plus框架是基于mybatis框架的,为了看是否把数据查询出来,直接在ResultSetHandler上把一个dubug就好。在默认情况下,mybatis框架使用的ResultSetHandler为DefaultResultSetHandler,当查询mybatis查询完毕后,会通过ResultSetHandler的handleResultSets(Statement stmt)方法对查询的数据结果集进行封装

SouthEast 3所以将断点打在handlerResultSets方法上最为合适。

再通过statement -> wrapper ->results -> rowData ->rows观察发现如下数据:

SouthEast 4

查询返回的结果集中rows的记录数为1,第1个字段的ascii为49,而49是ascii中数字1的值。而第二个字段也有值,说明所对应的timestamp字段是有返回值的,数据库查询是没有问题的。

然而通过mybatis代码进一步封装后的数据multipleResults又表示,只查询到了类型为Int的字段的数据

SouthEast 5这么也就是说,问题应该是出在了multipleResults的赋值问题上了

handleResultSets的完整代码为:

  1. //
  2. // HANDLE RESULT SETS
  3. //
  4. @Override
  5. public List<Object> handleResultSets(Statement stmt) throws SQLException {
  6. ErrorContext.instance().activity("handling results").object(mappedStatement.getId());
  7. final List<Object> multipleResults = new ArrayList<Object>();
  8. int resultSetCount = 0;
  9. ResultSetWrapper rsw = getFirstResultSet(stmt);
  10. List<ResultMap> resultMaps = mappedStatement.getResultMaps();
  11. int resultMapCount = resultMaps.size();
  12. validateResultMapsCount(rsw, resultMapCount);
  13. while (rsw != null && resultMapCount > resultSetCount) {
  14. ResultMap resultMap = resultMaps.get(resultSetCount);
  15. handleResultSet(rsw, resultMap, multipleResults, null);
  16. rsw = getNextResultSet(stmt);
  17. cleanUpAfterHandlingResultSet();
  18. resultSetCount++;
  19. }
  20. String[] resultSets = mappedStatement.getResultSets();
  21. if (resultSets != null) {
  22. while (rsw != null && resultSetCount < resultSets.length) {
  23. ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);
  24. if (parentMapping != null) {
  25. String nestedResultMapId = parentMapping.getNestedResultMapId();
  26. ResultMap resultMap = configuration.getResultMap(nestedResultMapId);
  27. handleResultSet(rsw, resultMap, null, parentMapping);
  28. }
  29. rsw = getNextResultSet(stmt);
  30. cleanUpAfterHandlingResultSet();
  31. resultSetCount++;
  32. }
  33. }
  34. return collapseSingleResultList(multipleResults);
  35. }

说明问题出在 handleResultSet(rsw, resultMap, multipleResults, null)*;这句代码上了*

通过代码跟踪,发现如下代码:

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

继而发现如下的核心代码:

  1. private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
  2. List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);
  3. boolean foundValues = false;
  4. if (!autoMapping.isEmpty()) {
  5. for (UnMappedColumnAutoMapping mapping : autoMapping) {
  6. final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);
  7. if (value != null) {
  8. foundValues = true;
  9. }
  10. if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {
  11. // gcode issue #377, call setter on nulls (value is not 'found')
  12. metaObject.setValue(mapping.property, value);
  13. }
  14. }
  15. }
  16. return foundValues;
  17. }

通过断点发现以下数据

SouthEast 6

在获取这个查询的的返回字段时,只获取出来两个,即int类型和varchar类型的.

再通过跟踪发现了如下代码:

  1. private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {
  2. final String mapKey = resultMap.getId() + ":" + columnPrefix;
  3. List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);
  4. if (autoMapping == null) {
  5. autoMapping = new ArrayList<UnMappedColumnAutoMapping>();
  6. final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);
  7. for (String columnName : unmappedColumnNames) {
  8. String propertyName = columnName;
  9. if (columnPrefix != null && !columnPrefix.isEmpty()) {
  10. // When columnPrefix is specified,
  11. // ignore columns without the prefix.
  12. if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {
  13. propertyName = columnName.substring(columnPrefix.length());
  14. } else {
  15. continue;
  16. }
  17. }
  18. final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());
  19. if (property != null && metaObject.hasSetter(property)) {
  20. if (resultMap.getMappedProperties().contains(property)) {
  21. continue;
  22. }
  23. final Class<?> propertyType = metaObject.getSetterType(property);
  24. if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {
  25. final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);
  26. autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));
  27. } else {
  28. configuration.getAutoMappingUnknownColumnBehavior()
  29. .doAction(mappedStatement, columnName, property, propertyType);
  30. }
  31. } else {
  32. configuration.getAutoMappingUnknownColumnBehavior()
  33. .doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);
  34. }
  35. }
  36. autoMappingsCache.put(mapKey, autoMapping);
  37. }
  38. return autoMapping;
  39. }

直到看到这里

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

才知道问题所在了, configuration.isMapUnderscoreToCamelCase()的值为true,即开启了驼峰命令。所以查找字段时就找不到。

把之前的类似crt_time改为crtTime后,就可以了!

没想到这么一个小错误,让我纠结了这么久!还好能跟踪源码!

通过这次的问题排查,让我明白了一个道理: 如果不知道某个框架原理的情况下,不要随便填写它的配置信息。在享受到框架的便捷性的同时,最好也得要明白它的原理,这样当出现问题时,才好快速定位。

发表评论

表情:
评论列表 (有 0 条评论,295人围观)

还没有评论,来说两句吧...

相关阅读