1. 程式人生 > >MyBatis 學習記錄7 一個Bug引發的思考

MyBatis 學習記錄7 一個Bug引發的思考

主題

  這次學習MyBatis的主題我想記錄一個使用起來可能會遇到,但是沒有經驗的話很不好解決的BUG,在特定情況下很容易發生.

 

異常

java.lang.IllegalArgumentException: Mapped Statements collection already contains value for com.xxx.package.ClassA.fun1

這個錯誤非常非常常見,百度一下大部分問題都能解決.這個問題90%出現的原因是一個Mapper檔案中有2個節點的id相同就會出現. 只要仔細檢查下id就OK了. 

可能很多問題Mybatis都會報這個錯,id重複是其中之一,也是最常見的,這點上來說MyBatis的錯誤提示不夠好.

 

現在我來分享一種情況也會出現這個錯誤,但是不是id重複的情況.

1.用MyBatis Generator自動生成Mapper和XML,並且

<javaClientGenerator targetPackage="" targetProject="" type="MIXEDMAPPER"/>

type="MIXEDMAPPER" 也就是自定生成的檔案是混用註解和XML的時候有一定概率產生.

這種生成下Mapper中的select語句有註解@ResultMap, 同時resultMap是定義在XML中的.

 

2.因為一般專案自動生成的XML和自己手寫的會分開,所以會有多個XML

. 並且自己定義的XML中也有resultMap.

 

3.一點點運氣,這個和XML載入順序有關係,在idea沒有打成jar包,也就是檔案是按檔名排序的時候不會有概率問題(開發debug載入順序是確定的),但是mapper.XML被打成jar在jar裡的時候載入順序不是按照字母順序,(釋出打成jar釋出到生產上的時候看起來是亂序)的時候就有一定概率發生(不是必現錯誤,需要看當時XML的載入順序)

 

原理

正如之前文章分享的那樣,MyBatis在啟動的時候會讀取Mapper XML去解析生產MapperedStatement.

假設我有1個Mapper A, 對應XML1和XML2.  2個XML檔案.

A.fun1方法上有@ResultMap註解,在XML2中定義對應的resultMap.

 

啟動的時候如果先讀取到了XML1這個XML. 這個時候會呼叫XMLMapperBuilder.parse

  public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
      configurationElement(parser.evalNode("/mapper"));
      configuration.addLoadedResource(resource);
      bindMapperForNamespace();
    }

    parsePendingResultMaps();
    parsePendingCacheRefs();
    parsePendingStatements();
  }