mybatis錯誤之Could not find result map java.util.List

1.復現錯誤

報錯提示:

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

2.背景

首先去官網確認一下resultMap和resultType的用法自己用對了,本文不討論基本用法,所以針對已經熟練運用myabtis後的錯誤

官網:http://www.mybatis.org/mybatis-3/zh/sqlmap-xml.html#select

3.復現場景

(1)Dao層有兩個方法,記住這兩個fast是正常的,test是錯誤的

int selectFast();

int selectTest();

(2)對應xml,其中selectTest是有問題的, resultMap="java.util.List" 這樣寫是錯誤的

<select id="selectFast" resultType="java.lang.Integer">
    select count(1) from sys_user
</select>

<select id="selectTest" resultMap="java.util.List">
    select count(1) from sys_user
</select>

(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();方法正常,再次訪問提示正常。

<select id="selectTest" resultType="java.lang.Integer">
    select count(1) from sys_user
</select>

當時的解決思路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編譯,啓動都不報錯,在請求正常接口的時候,報一個不相干方法的錯誤,這個提示位置是有問題的,就會導致大家排查問題浪費大量時間,先記住會有這個問題吧,以後會避免一個坑。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章