报错提示:
13:41:33.539 ERROR com.fast.framework.advice.FastBootControllerAdvice 58 errorHandler - Could not find result map java.util.List org.apache.ibatis.builder.IncompleteElementException: Could not find result map java.util.List
at org.apache.ibatis.builder.MapperBuilderAssistant.getStatementResultMaps(MapperBuilderAssistant.java:346) ~[mybatis-3.5.0.jar:3.5.0]
at org.apache.ibatis.builder.MapperBuilderAssistant.addMappedStatement(MapperBuilderAssistant.java:290) ~[mybatis-3.5.0.jar:3.5.0]
at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:109) ~[mybatis-3.5.0.jar:3.5.0]
at org.apache.ibatis.session.Configuration.lambda$buildAllStatements$2(Configuration.java:787) ~[mybatis-3.5.0.jar:3.5.0]
at java.util.Collection.removeIf(Collection.java:414) ~[?:1.8.0_112]
at org.apache.ibatis.session.Configuration.buildAllStatements(Configuration.java:786) ~[mybatis-3.5.0.jar:3.5.0]
at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:763) ~[mybatis-3.5.0.jar:3.5.0]
at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:758) ~[mybatis-3.5.0.jar:3.5.0]
at com.baomidou.mybatisplus.core.override.MybatisMapperMethod$SqlCommand.resolveMappedStatement(MybatisMapperMethod.java:264) ~[mybatis-plus-core-3.1.0
首先去官网确认一下resultMap和resultType的用法自己用对了,本文不讨论基本用法,所以针对已经熟练运用myabtis后的错误
官网:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#select
(1)Dao层有两个方法,记住这两个fast是正常的,test是错误的
int selectFast();
int selectTest();
(2)对应xml,其中selectTest是有问题的, resultMap="java.util.List" 这样写是错误的
(3)然后我只调用正常的那个方法int selectFast();
masterDao.selectFast()
(4)正常的maven clean,install,package都正常
(5)编译完启动,也正常启动
(6)然后在通过controller调用正常的方法selectFast的时候报最开始那个错了
Could not find result map java.util.List
(7)类似这个错误会有个提示错误发生的位置,这个错误的提示是:
at com.fast.web.controller.TestController.getString(TestController.java:25) ~[classes/:?]
就是这个TestController的25行,我也是调用的这个方法,按理说都正确
(8)但是不正确的问题是哪里?
我当前调用的这个方法int selectFast();是正常的啊,代码没有问题,并且调用的接口也只是这个方法,所以代码应该正常执行啊。
但是mybatis返回错误了,返回了一个与当时接口调用,不相干的一个方法(int selectTest();)的错误,然而这个错误,在编译阶段,启动阶段都没有报错。在调用其他方法的时候,提示了这个方法的错误,并且提示的有错误的位置是正确方法的位置。
思路:先解决问题再搞清问题,直接把不相干方法的错误改掉,如下修改,int selectTest();方法正常,再次访问提示正常。
当时的解决思路debug:因为我请求的正常方法,返回参数应该是resultType的,但是这个resultMap是哪里来的,并且还报错了,看mybatis提示错误信息位置,
14:04:46.787 ERROR com.fast.framework.advice.FastBootControllerAdvice 58 errorHandler - Could not find result map java.util.List org.apache.ibatis.builder.IncompleteElementException: Could not find result map java.util.List
at org.apache.ibatis.builder.MapperBuilderAssistant.getStatementResultMaps(MapperBuilderAssistant.java:346) ~[mybatis-3.5.0.jar:3.5.0]
at org.apache.ibatis.builder.MapperBuilderAssistant.addMappedStatement(MapperBuilderAssistant.java:290) ~[mybatis-3.5.0.jar:3.5.0]
at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:109) ~[mybatis-3.5.0.jar:3.5.0]
at org.apache.ibatis.session.Configuration.lambda$buildAllStatements$2(Configuration.java:787) ~[mybatis-3.5.0.jar:3.5.0]
at java.util.Collection.removeIf(Collection.java:414) ~[?:1.8.0_112]
找到这个(XMLStatementBuilder.java:109)打个断点,下面是mybatis源码,断点位置放在最后一行。
重新请求,看发过来的resultMap参数
public void parseStatementNode() {
String id = this.context.getStringAttribute("id");
String databaseId = this.context.getStringAttribute("databaseId");
if (this.databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) {
Integer fetchSize = this.context.getIntAttribute("fetchSize");
Integer timeout = this.context.getIntAttribute("timeout");
String parameterMap = this.context.getStringAttribute("parameterMap");
String parameterType = this.context.getStringAttribute("parameterType");
Class> parameterTypeClass = this.resolveClass(parameterType);
String resultMap = this.context.getStringAttribute("resultMap");
String resultType = this.context.getStringAttribute("resultType");
String lang = this.context.getStringAttribute("lang");
LanguageDriver langDriver = this.getLanguageDriver(lang);
Class> resultTypeClass = this.resolveClass(resultType);
String resultSetType = this.context.getStringAttribute("resultSetType");
StatementType statementType = StatementType.valueOf(this.context.getStringAttribute("statementType", StatementType.PREPARED.toString()));
ResultSetType resultSetTypeEnum = this.resolveResultSetType(resultSetType);
String nodeName = this.context.getNode().getNodeName();
SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = this.context.getBooleanAttribute("flushCache", !isSelect);
boolean useCache = this.context.getBooleanAttribute("useCache", isSelect);
boolean resultOrdered = this.context.getBooleanAttribute("resultOrdered", false);
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(this.configuration, this.builderAssistant);
includeParser.applyIncludes(this.context.getNode());
this.processSelectKeyNodes(id, parameterTypeClass, langDriver);
SqlSource sqlSource = langDriver.createSqlSource(this.configuration, this.context, parameterTypeClass);
String resultSets = this.context.getStringAttribute("resultSets");
String keyProperty = this.context.getStringAttribute("keyProperty");
String keyColumn = this.context.getStringAttribute("keyColumn");
String keyStatementId = id + "!selectKey";
keyStatementId = this.builderAssistant.applyCurrentNamespace(keyStatementId, true);
Object keyGenerator;
if (this.configuration.hasKeyGenerator(keyStatementId)) {
keyGenerator = this.configuration.getKeyGenerator(keyStatementId);
} else {
keyGenerator = this.context.getBooleanAttribute("useGeneratedKeys", this.configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType)) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE;
}
this.builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, (KeyGenerator)keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
}
}
然后查看debug参数,我这个接口请求的是selectFast()的啊,正常的方法,但是现在也校验了selectTest();这个有问题的方法。
resultMap返回java.util.List
所以全局搜selectTest这个方法,修改返回参数,完成bug修复。
总结:这个bug不是什么比较复杂的bug,也不是什么有意义的bug,但是mybatis编译,启动都不报错,在请求正常接口的时候,报一个不相干方法的错误,这个提示位置是有问题的,就会导致大家排查问题浪费大量时间,先记住会有这个问题吧,以后会避免一个坑。