1. 程式人生 > >org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)異常處理

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found)異常處理

一、問題描述
在做spring cloud微服務專案開發時,在進行其中一個微服務啟動時,先是出現如下異常資訊:

java.io.FileNotFoundException: class path resource [mapper/] cannot be resolved to URL because it does not exist
    at org.springframework.core.io.ClassPathResource.getURL(ClassPathResource.java:187)
    at org.springframework.core.io.support
.PathMatchingResourcePatternResolver.findPathMatchingResources(PathMatchingResourcePatternResolver.java:464) at org.springframework.core.io.support.PathMatchingResourcePatternResolver.getResources(PathMatchingResourcePatternResolver.java:293) at org.NumberRecovery.utils.MyBatisConfig.sqlSessionFactory
(MyBatisConfig.java:57) at org.NumberRecovery.utils.MyBatisConfig$$EnhancerBySpringCGLIB$$6977a288.CGLIB$sqlSessionFactory$1(<generated>) at org.NumberRecovery.utils.MyBatisConfig$$EnhancerBySpringCGLIB$$6977a288$$FastClassBySpringCGLIB$$d8fb1cdb.invoke(<generated>) at org.springframework
.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:358) at org.NumberRecovery.utils.MyBatisConfig$$EnhancerBySpringCGLIB$$6977a288.sqlSessionFactory(<generated>) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)

網路搜尋相關解決方案後,修改application.properties配置檔案中mybatis.mapperLocations=classpath:mapper/*.xml

mybatis.mapperLocations=classpath*:mapper/*.xml
(我的用來存放mapper.xml檔案的mapper目錄直接放到src/main/resources目錄下),暫時解決,相關原因可以搜尋classpath*與classpath區別的相關文章或部落格
但再次啟動程式,又出現如下異常資訊:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): org.NumberRecovery.dao.NumberMapper.qryLockNumber
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:225)
    at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:48)
    at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58)
    at com.sun.proxy.$Proxy99.qryLockNumber(Unknown Source)
    at org.NumberRecovery.service.RecoveryService.qryLockNumber(RecoveryService.java:24)
    at org.NumberRecovery.service.RecoveryService$$FastClassBySpringCGLIB$$dc43da81.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
    at org.NumberRecovery.service.RecoveryService$$EnhancerBySpringCGLIB$$b33476fe.qryLockNumber(<generated>)
    at org.NumberRecovery.controller.RecoveryController.updateLockNumber(RecoveryController.java:39)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

二、問題解決

出現異常後,就開始了漫長的網路搜尋解決方案之旅,可以查到很多這種異常的相關部落格或說明,但基本內容都差不多,我這裡先列舉一下,前面五條可能原因不是我自己總結出來的,這裡只是新增一下我自己的實際經驗,然後加上我自己解決時遇到的問題,通常可能導致這個異常出現的原因有以下幾種:

(1) mapper介面類和mapper.xml是否在同一個包下,檔名稱是否一致(僅字尾不同):經過實際檢驗,這個並不需要在同一個包下面,通常mapper.xml檔案是存放在src/main/resources目錄下,而mapper介面類是在src/main/java目錄下面;名稱是否相同也不重要,我的命名分貝為NumberDao.java和NumberMapper.xml,實際也可以執行成功
(2)mapper.xml的namespace是否是對應介面類的全名(包括包名和類名):這個是必須要保證相同,需要進行檢查,而且全類名最好通過複製,不要自己手動拼寫,容易出錯
(3)mapper介面類的方法名是否與mapper.xml中sql標籤的id相同:這個也需要進行檢查,必須保證一致
(4)mapper.xml檔案中用resultMap,而不用resultType(當sql操作結果是List或其他複雜結果集時):我經過實踐檢驗,我的查詢結果是一個Integer的List集合,用resultMap反而報錯,異常資訊如下:

org.apache.ibatis.builder.IncompleteElementException: Could not find result map java.lang.Integer
    at org.apache.ibatis.builder.MapperBuilderAssistant.getStatementResultMaps(MapperBuilderAssistant.java:346)
    at org.apache.ibatis.builder.MapperBuilderAssistant.addMappedStatement(MapperBuilderAssistant.java:290)
    at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:109)
    at org.apache.ibatis.session.Configuration.buildAllStatements(Configuration.java:788)
    at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:758)
    at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:753)
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.resolveMappedStatement(MapperMethod.java:247)
    at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:217)
    at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:48)
    at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:65)
    at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:58)
    at com.sun.proxy.$Proxy99.qryLockNumber(Unknown Source)
    at org.NumberRecovery.service.RecoveryService.qryLockNumber(RecoveryService.java:23)
    at org.NumberRecovery.service.RecoveryService$$FastClassBySpringCGLIB$$dc43da81.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
    at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:281)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:673)
    at org.NumberRecovery.service.RecoveryService$$EnhancerBySpringCGLIB$$a9c68bd2.qryLockNumber(<generated>)
    at org.NumberRecovery.controller.RecoveryController.updateLockNumber(RecoveryController.java:39)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
    at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.util.concurrent.FutureTask.runAndReset(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: Result Maps collection does not contain value for java.lang.Integer
    at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:888)
    at org.apache.ibatis.session.Configuration.getResultMap(Configuration.java:640)
    at org.apache.ibatis.builder.MapperBuilderAssistant.getStatementResultMaps(MapperBuilderAssistant.java:344)
    ... 36 common frames omitted

(5) 到target目錄下看是否有mapper.xml檔案生成(按照自己對mapper.xml檔案的路徑配置到target下classes目錄下找),如果沒有可以在pom.xml檔案的<build></build>之間新增

<resources>
     <resource>
          <directory>src/main/resources</directory>
          <includes>
              <include>**/*.xml</include>
          </includes>
     </resource>
 </resources>

也可以再在<resources></resources>之間再新增一項

<resource>
    <directory>src/main/java</directory>
    <includes>
        <include>**/*.xml</include>
    </includes>
</resource>

使mapper.xml檔案不論是放在src/main/resourcessrc/main/java下都可以被打包到classes目錄下。

(6)前面幾項的可能原因都是我從網路上查詢到的,做了所有的修改和檢查,也沒有解決問題,然後發現我要說明的這最後一項才是我這次遇到的問題,這個經歷非常坑,完全沒有考慮到出現這次的問題的情況,用了我整整一天加一晚上的時間……..非常無語。
就是我的專案程式碼最開始是在我這裡開發的,組內另外一名同事用的是IDEA開發,他在向git上提交時,把一個.idea的目錄也上傳到git上(沒用過IDEA,不清楚這個目錄的作用)。我checkout到本地後,發現出現上述異常,怎麼都改不好。最後我在本地刪除了.idea目錄,然後程式居然正常執行起來了,正常執行起來了,正常執行起來了!!!!!!
怎麼也沒想到是因為兩個IDE之間還會有這種影響,還是經驗不足,對其他的IDE瞭解不到位造成用了這麼多時間都沒有解決問題。。。。。。

經過此次問題解決,必須得寫下來作為文字記錄這個過程和解決問題的原因!防止以後再次遇到這種問題束手無策!同時也可以給其他遇到這個問題的小夥伴兒提供一個可能的解決問題的方向。